Module: Enumerable

Included in:
ARGF, Array, Dir, Enumerator, Enumerator::Generator, Hash, IO, ObjectSpace::WeakMap, Range, Struct
Defined in:
enum.c

Overview

The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to sort. The class must provide a method each, which yields successive members of the collection. If Enumerable#max, #min, or #sort is used, the objects in the collection must also implement a meaningful <=> operator, as these methods rely on an ordering between members of the collection.

Instance Method Summary (collapse)

Instance Method Details

- (Boolean) all? {|obj| ... }

Passes each element of the collection to the given block. The method returns true if the block never returns false or nil. If the block is not given, Ruby adds an implicit block of { |obj| obj } which will cause #all? to return true when none of the collection members are false or nil.

%w[ant bear cat].all? { |word| word.length >= 3 } #=> true
%w[ant bear cat].all? { |word| word.length >= 4 } #=> false
[nil, true, 99].all?                              #=> false

Yields:

  • (obj)


1052
1053
1054
1055
1056
1057
1058
# File 'enum.c', line 1052

static VALUE
enum_all(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qtrue, 0, 0);
    rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo);
    return memo->u1.value;
}

- (Boolean) any? {|obj| ... }

Passes each element of the collection to the given block. The method returns true if the block ever returns a value other than false or nil. If the block is not given, Ruby adds an implicit block of { |obj| obj } that will cause #any? to return true if at least one of the collection members is not false or nil.

%w[ant bear cat].any? { |word| word.length >= 3 } #=> true
%w[ant bear cat].any? { |word| word.length >= 4 } #=> true
[nil, true, 99].any?                              #=> true

Yields:

  • (obj)


1086
1087
1088
1089
1090
1091
1092
# File 'enum.c', line 1086

static VALUE
enum_any(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qfalse, 0, 0);
    rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
    return memo->u1.value;
}

- (Object) chunk {|elt| ... } - (Object) chunk(initial_state) {|elt, state| ... }

Enumerates over the items, chunking them together based on the return value of the block.

Consecutive elements which return the same block value are chunked together.

For example, consecutive even numbers and odd numbers can be chunked as follows.

[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n|
  n.even?
}.each { |even, ary|
  p [even, ary]
}
#=> [false, [3, 1]]
#   [true, [4]]
#   [false, [1, 5, 9]]
#   [true, [2, 6]]
#   [false, [5, 3, 5]]

This method is especially useful for sorted series of elements. The following example counts words for each initial letter.

open("/usr/share/dict/words", "r:iso-8859-1") { |f|
  f.chunk { |line| line.ord }.each { |ch, lines| p [ch.chr, lines.length] }
}
#=> ["\n", 1]
#   ["A", 1327]
#   ["B", 1372]
#   ["C", 1507]
#   ["D", 791]
#   ...

The following key values have special meaning:

  • nil and :_separator specifies that the elements should be dropped.

  • :_alone specifies that the element should be chunked by itself.

Any other symbols that begin with an underscore will raise an error:

items.chunk { |item| :_underscore }
#=> RuntimeError: symbols beginning with an underscore are reserved

nil and :_separator can be used to ignore some elements.

For example, the sequence of hyphens in svn log can be eliminated as follows:

sep = "-"*72 + "\n"
IO.popen("svn log README") { |f|
  f.chunk { |line|
    line != sep || nil
  }.each { |_, lines|
    pp lines
  }
}
#=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n",
#    "\n",
#    "* README, README.ja: Update the portability section.\n",
#    "\n"]
#   ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n",
#    "\n",
#    "* README, README.ja: Add a note about default C flags.\n",
#    "\n"]
#   ...

Paragraphs separated by empty lines can be parsed as follows:

File.foreach("README").chunk { |line|
  /\A\s*\z/ !~ line || nil
}.each { |_, lines|
  pp lines
}

:_alone can be used to force items into their own chunk. For example, you can put lines that contain a URL by themselves, and chunk the rest of the lines together, like this:

pattern = /http/
open(filename) { |f|
  f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines|
    pp lines
  }
}

If the block needs to maintain state over multiple elements, an initial_state argument can be used. If a non-nil value is given, a reference to it is passed as the 2nd argument of the block for the chunk method, so state-changes to it persist across block calls.

Overloads:

  • - (Object) chunk {|elt| ... }

    Yields:

    • (elt)
  • - (Object) chunk(initial_state) {|elt, state| ... }

    Yields:

    • (elt, state)


2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
# File 'enum.c', line 2541

static VALUE
enum_chunk(int argc, VALUE *argv, VALUE enumerable)
{
    VALUE initial_state;
    VALUE enumerator;

    if (!rb_block_given_p())
	rb_raise(rb_eArgError, "no block given");
    rb_scan_args(argc, argv, "01", &initial_state);

    enumerator = rb_obj_alloc(rb_cEnumerator);
    rb_ivar_set(enumerator, rb_intern("chunk_enumerable"), enumerable);
    rb_ivar_set(enumerator, rb_intern("chunk_categorize"), rb_block_proc());
    rb_ivar_set(enumerator, rb_intern("chunk_initial_state"), initial_state);
    rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator);
    return enumerator;
}

- (Array) collect {|obj| ... } - (Array) map {|obj| ... } - (Object) collect - (Object) map

Returns a new array with the results of running block once for every element in enum.

If no block is given, an enumerator is returned instead.

(1..4).map { |i| i*i }      #=> [1, 4, 9, 16]
(1..4).collect { "cat"  }   #=> ["cat", "cat", "cat", "cat"]

Overloads:

  • - (Array) collect {|obj| ... }

    Yields:

    • (obj)
  • - (Array) map {|obj| ... }

    Yields:

    • (obj)


428
429
430
431
432
433
434
435
436
437
438
439
# File 'enum.c', line 428

static VALUE
enum_collect(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, collect_i, ary);

    return ary;
}

- (Array) flat_map {|obj| ... } - (Array) collect_concat {|obj| ... } - (Object) flat_map - (Object) collect_concat

Returns a new array with the concatenated results of running block once for every element in enum.

If no block is given, an enumerator is returned instead.

[1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
[[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]

Overloads:

  • - (Array) flat_map {|obj| ... }

    Yields:

    • (obj)
  • - (Array) collect_concat {|obj| ... }

    Yields:

    • (obj)


475
476
477
478
479
480
481
482
483
484
485
486
# File 'enum.c', line 475

static VALUE
enum_flat_map(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);

    return ary;
}

- (Integer) count - (Integer) count(item) - (Integer) count {|obj| ... }

Returns the number of items in enum through enumeration. If an argument is given, the number of items in enum that are equal to item are counted. If a block is given, it counts the number of elements yielding a true value.

ary = [1, 2, 4, 2]
ary.count               #=> 4
ary.count(2)            #=> 2
ary.count{ |x| x%2==0 } #=> 3

Overloads:

  • - (Integer) count {|obj| ... }

    Yields:

    • (obj)


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'enum.c', line 150

static VALUE
enum_count(int argc, VALUE *argv, VALUE obj)
{
    VALUE item = Qnil;
    NODE *memo;
    rb_block_call_func *func;

    if (argc == 0) {
	if (rb_block_given_p()) {
	    func = count_iter_i;
	}
	else {
	    func = count_all_i;
	}
    }
    else {
	rb_scan_args(argc, argv, "1", &item);
	if (rb_block_given_p()) {
	    rb_warn("given block not used");
	}
        func = count_i;
    }

    memo = NEW_MEMO(item, 0, 0);
    rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
    return INT2NUM(memo->u3.cnt);
}

- (nil) cycle(n = nil) {|obj| ... } - (Object) cycle(n = nil)

Calls block for each element of enum repeatedly n times or forever if none or nil is given. If a non-positive number is given or the collection is empty, does nothing. Returns nil if the loop has finished without getting interrupted.

Enumerable#cycle saves elements in an internal array so changes to enum after the first pass have no effect.

If no block is given, an enumerator is returned instead.

a = ["a", "b", "c"]
a.cycle { |x| puts x }  # print, a, b, c, a, b, c,.. forever.
a.cycle(2) { |x| puts x }  # print, a, b, c, a, b, c.

Overloads:

  • - (nil) cycle(n = nil) {|obj| ... }

    Yields:

    • (obj)


2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
# File 'enum.c', line 2335

static VALUE
enum_cycle(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary;
    VALUE nv = Qnil;
    long n, i, len;

    rb_scan_args(argc, argv, "01", &nv);

    RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size);
    if (NIL_P(nv)) {
        n = -1;
    }
    else {
        n = NUM2LONG(nv);
        if (n <= 0) return Qnil;
    }
    ary = rb_ary_new();
    RBASIC_CLEAR_CLASS(ary);
    rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
    len = RARRAY_LEN(ary);
    if (len == 0) return Qnil;
    while (n < 0 || 0 < --n) {
        for (i=0; i<len; i++) {
            rb_yield(RARRAY_AREF(ary, i));
        }
    }
    return Qnil;
}

- (Object?) detect(ifnone = nil) {|obj| ... } - (Object?) find(ifnone = nil) {|obj| ... } - (Object) detect(ifnone = nil) - (Object) find(ifnone = nil)

Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns nil otherwise.

If no block is given, an enumerator is returned instead.

(1..10).detect  { |i| i % 5 == 0 and i % 7 == 0 }   #=> nil
(1..100).detect { |i| i % 5 == 0 and i % 7 == 0 }   #=> 35

Overloads:

  • - (Object?) detect(ifnone = nil) {|obj| ... }

    Yields:

    • (obj)
  • - (Object?) find(ifnone = nil) {|obj| ... }

    Yields:

    • (obj)


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'enum.c', line 211

static VALUE
enum_find(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;
    VALUE if_none;

    rb_scan_args(argc, argv, "01", &if_none);
    RETURN_ENUMERATOR(obj, argc, argv);
    memo = NEW_MEMO(Qundef, 0, 0);
    rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
    if (memo->u3.cnt) {
	return memo->u1.value;
    }
    if (!NIL_P(if_none)) {
	return rb_funcall(if_none, id_call, 0, 0);
    }
    return Qnil;
}

- (Array) drop(n)

Drops first n elements from enum, and returns rest elements in an array.

a = [1, 2, 3, 4, 5, 0]
a.drop(3)             #=> [4, 5, 0]


2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
# File 'enum.c', line 2224

static VALUE
enum_drop(VALUE obj, VALUE n)
{
    VALUE result;
    NODE *memo;
    long len = NUM2LONG(n);

    if (len < 0) {
	rb_raise(rb_eArgError, "attempt to drop negative size");
    }

    result = rb_ary_new();
    memo = NEW_MEMO(result, 0, len);
    rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
    return result;
}

- (Array) drop_while {|arr| ... } - (Object) drop_while

Drops elements up to, but not including, the first element for which the block returns nil or false and returns an array containing the remaining elements.

If no block is given, an enumerator is returned instead.

a = [1, 2, 3, 4, 5, 0]
a.drop_while { |i| i < 3 }   #=> [3, 4, 5, 0]

Overloads:

  • - (Array) drop_while {|arr| ... }

    Yields:

    • (arr)


2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
# File 'enum.c', line 2273

static VALUE
enum_drop_while(VALUE obj)
{
    VALUE result;
    NODE *memo;

    RETURN_ENUMERATOR(obj, 0, 0);
    result = rb_ary_new();
    memo = NEW_MEMO(result, 0, FALSE);
    rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
    return result;
}

- (nil) each_cons(n) { ... } - (Object) each_cons(n)

Iterates the given block for each array of consecutive <n> elements. If no block is given, returns an enumerator.

e.g.:

(1..10).each_cons(3) { |a| p a }
# outputs below
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 10]

Overloads:

  • - (nil) each_cons(n) { ... }

    Yields:



1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
# File 'enum.c', line 1940

static VALUE
enum_each_cons(VALUE obj, VALUE n)
{
    long size = NUM2LONG(n);
    NODE *memo;

    if (size <= 0) rb_raise(rb_eArgError, "invalid size");
    RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
    memo = NEW_MEMO(rb_ary_new2(size), 0, size);
    rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);

    return Qnil;
}

- (Enumerator) each_entry {|obj| ... } - (Object) each_entry

Calls block once for each element in self, passing that element as a parameter, converting multiple values from yield to an array.

If no block is given, an enumerator is returned instead.

class Foo
  include Enumerable
  def each
    yield 1
    yield 1, 2
    yield
  end
end
Foo.new.each_entry{ |o| p o }

produces:

1
[1, 2]
nil

Overloads:

  • - (Enumerator) each_entry {|obj| ... }

    Yields:

    • (obj)


1811
1812
1813
1814
1815
1816
1817
# File 'enum.c', line 1811

static VALUE
enum_each_entry(int argc, VALUE *argv, VALUE obj)
{
    RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
    rb_block_call(obj, id_each, argc, argv, each_val_i, 0);
    return obj;
}

- (nil) each_slice(n) { ... } - (Object) each_slice(n)

Iterates the given block for each slice of <n> elements. If no block is given, returns an enumerator.

(1..10).each_slice(3) { |a| p a }
# outputs below
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]

Overloads:

  • - (nil) each_slice(n) { ... }

    Yields:



1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
# File 'enum.c', line 1868

static VALUE
enum_each_slice(VALUE obj, VALUE n)
{
    long size = NUM2LONG(n);
    VALUE ary;
    NODE *memo;

    if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
    RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size);
    ary = rb_ary_new2(size);
    memo = NEW_MEMO(ary, 0, size);
    rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
    ary = memo->u1.value;
    if (RARRAY_LEN(ary) > 0) rb_yield(ary);

    return Qnil;
}

- (Enumerator) each_with_index(*args) {|obj, i| ... } - (Object) each_with_index(*args)

Calls block with two arguments, the item and its index, for each item in enum. Given arguments are passed through to #each().

If no block is given, an enumerator is returned instead.

hash = Hash.new
%w(cat dog wombat).each_with_index { |item, index|
  hash[item] = index
}
hash   #=> {"cat"=>0, "dog"=>1, "wombat"=>2}

Overloads:

  • - (Enumerator) each_with_index(*args) {|obj, i| ... }

    Yields:

    • (obj, i)


1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
# File 'enum.c', line 1725

static VALUE
enum_each_with_index(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;

    RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);

    memo = NEW_MEMO(0, 0, 0);
    rb_block_call(obj, id_each, argc, argv, each_with_index_i, (VALUE)memo);
    return obj;
}

- (Object) each_with_object(obj) {|(*args), memo_obj| ... } - (Object) each_with_object(obj)

Iterates the given block for each element with an arbitrary object given, and returns the initially given object.

If no block is given, returns an enumerator.

evens = (1..10).each_with_object([]) { |i, a| a << i*2 }
#=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Overloads:

  • - (Object) each_with_object(obj) {|(*args), memo_obj| ... }

    Yields:

    • ((*args), memo_obj)


1975
1976
1977
1978
1979
1980
1981
1982
1983
# File 'enum.c', line 1975

static VALUE
enum_each_with_object(VALUE obj, VALUE memo)
{
    RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enum_size);

    rb_block_call(obj, id_each, 0, 0, each_with_object_i, memo);

    return memo;
}

- (Array) to_a(*args) - (Array) entries(*args)

Returns an array containing the items in enum.

(1..7).to_a                       #=> [1, 2, 3, 4, 5, 6, 7]
{ 'a'=>1, 'b'=>2, 'c'=>3 }.to_a   #=> [["a", 1], ["b", 2], ["c", 3]]

require 'prime'
Prime.entries 10                  #=> [2, 3, 5, 7]


501
502
503
504
505
506
507
508
509
510
# File 'enum.c', line 501

static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary = rb_ary_new();

    rb_block_call(obj, id_each, argc, argv, collect_all, ary);
    OBJ_INFECT(ary, obj);

    return ary;
}

- (Object?) detect(ifnone = nil) {|obj| ... } - (Object?) find(ifnone = nil) {|obj| ... } - (Object) detect(ifnone = nil) - (Object) find(ifnone = nil)

Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns nil otherwise.

If no block is given, an enumerator is returned instead.

(1..10).detect  { |i| i % 5 == 0 and i % 7 == 0 }   #=> nil
(1..100).detect { |i| i % 5 == 0 and i % 7 == 0 }   #=> 35

Overloads:

  • - (Object?) detect(ifnone = nil) {|obj| ... }

    Yields:

    • (obj)
  • - (Object?) find(ifnone = nil) {|obj| ... }

    Yields:

    • (obj)


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'enum.c', line 211

static VALUE
enum_find(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;
    VALUE if_none;

    rb_scan_args(argc, argv, "01", &if_none);
    RETURN_ENUMERATOR(obj, argc, argv);
    memo = NEW_MEMO(Qundef, 0, 0);
    rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
    if (memo->u3.cnt) {
	return memo->u1.value;
    }
    if (!NIL_P(if_none)) {
	return rb_funcall(if_none, id_call, 0, 0);
    }
    return Qnil;
}

- (Array) find_all {|obj| ... } - (Array) select {|obj| ... } - (Object) find_all - (Object) select

Returns an array containing all elements of enum for which the given block returns a true value.

If no block is given, an Enumerator is returned instead.

(1..10).find_all { |i|  i % 3 == 0 }   #=> [3, 6, 9]

[1,2,3,4,5].select { |num|  num.even?  }   #=> [2, 4]

See also Enumerable#reject.

Overloads:

  • - (Array) find_all {|obj| ... }

    Yields:

    • (obj)
  • - (Array) select {|obj| ... }

    Yields:

    • (obj)


340
341
342
343
344
345
346
347
348
349
350
351
# File 'enum.c', line 340

static VALUE
enum_find_all(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, find_all_i, ary);

    return ary;
}

- (Integer?) find_index(value) - (Integer?) find_index {|obj| ... } - (Object) find_index

Compares each entry in enum with value or passes to block. Returns the index for the first for which the evaluated value is non-false. If no object matches, returns nil

If neither block nor argument is given, an enumerator is returned instead.

(1..10).find_index  { |i| i % 5 == 0 and i % 7 == 0 }  #=> nil
(1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 }  #=> 34
(1..100).find_index(50)                                #=> 49

Overloads:

  • - (Integer?) find_index {|obj| ... }

    Yields:

    • (obj)


277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'enum.c', line 277

static VALUE
enum_find_index(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;	/* [return value, current index, ] */
    VALUE condition_value = Qnil;
    rb_block_call_func *func;

    if (argc == 0) {
        RETURN_ENUMERATOR(obj, 0, 0);
        func = find_index_iter_i;
    }
    else {
	rb_scan_args(argc, argv, "1", &condition_value);
	if (rb_block_given_p()) {
	    rb_warn("given block not used");
	}
        func = find_index_i;
    }

    memo = NEW_MEMO(Qnil, condition_value, 0);
    rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
    return memo->u1.value;
}

- (Object?) first - (Array) first(n)

Returns the first element, or the first n elements, of the enumerable. If the enumerable is empty, the first form returns nil, and the second form returns an empty array.

%w[foo bar baz].first     #=> "foo"
%w[foo bar baz].first(2)  #=> ["foo", "bar"]
%w[foo bar baz].first(10) #=> ["foo", "bar", "baz"]
[].first                  #=> nil


794
795
796
797
798
799
800
801
802
803
804
805
806
807
# File 'enum.c', line 794

static VALUE
enum_first(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;
    rb_check_arity(argc, 0, 1);
    if (argc > 0) {
	return enum_take(obj, argv[0]);
    }
    else {
	memo = NEW_MEMO(Qnil, 0, 0);
	rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
	return memo->u1.value;
    }
}

- (Array) flat_map {|obj| ... } - (Array) collect_concat {|obj| ... } - (Object) flat_map - (Object) collect_concat

Returns a new array with the concatenated results of running block once for every element in enum.

If no block is given, an enumerator is returned instead.

[1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
[[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]

Overloads:

  • - (Array) flat_map {|obj| ... }

    Yields:

    • (obj)
  • - (Array) collect_concat {|obj| ... }

    Yields:

    • (obj)


475
476
477
478
479
480
481
482
483
484
485
486
# File 'enum.c', line 475

static VALUE
enum_flat_map(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);

    return ary;
}

- (Array) grep(pattern) - (Array) grep(pattern) {|obj| ... }

Returns an array of every element in enum for which Pattern === element. If the optional block is supplied, each matching element is passed to it, and the block's result is stored in the output array.

(1..100).grep 38..44   #=> [38, 39, 40, 41, 42, 43, 44]
c = IO.constants
c.grep(/SEEK/)         #=> [:SEEK_SET, :SEEK_CUR, :SEEK_END]
res = c.grep(/SEEK/) { |v| IO.const_get(v) }
res                    #=> [0, 1, 2]

Overloads:

  • - (Array) grep(pattern) {|obj| ... }

    Yields:

    • (obj)


88
89
90
91
92
93
94
95
96
97
# File 'enum.c', line 88

static VALUE
enum_grep(VALUE obj, VALUE pat)
{
    VALUE ary = rb_ary_new();
    NODE *memo = NEW_MEMO(pat, ary, 0);

    rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)memo);

    return ary;
}

- (Hash) group_by {|obj| ... } - (Object) group_by

Groups the collection by result of the block. Returns a hash where the keys are the evaluated result from the block and the values are arrays of elements in the collection that correspond to the key.

If no block is given an enumerator is returned.

(1..6).group_by { |i| i%3 }   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}

Overloads:

  • - (Hash) group_by {|obj| ... }

    Yields:

    • (obj)


750
751
752
753
754
755
756
757
758
759
760
761
762
# File 'enum.c', line 750

static VALUE
enum_group_by(VALUE obj)
{
    VALUE hash;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    hash = rb_hash_new();
    rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
    OBJ_INFECT(hash, obj);

    return hash;
}

- (Boolean) include?(obj) - (Boolean) member?(obj)

Returns true if any member of enum equals obj. Equality is tested using ==.

IO.constants.include? :SEEK_SET          #=> true
IO.constants.include? :SEEK_NO_FURTHER   #=> false


1689
1690
1691
1692
1693
1694
1695
1696
# File 'enum.c', line 1689

static VALUE
enum_member(VALUE obj, VALUE val)
{
    NODE *memo = NEW_MEMO(val, Qfalse, 0);

    rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
    return memo->u2.value;
}

- (Object) inject(initial, sym) - (Object) inject(sym) - (Object) inject(initial) {|memo, obj| ... } - (Object) inject {|memo, obj| ... } - (Object) reduce(initial, sym) - (Object) reduce(sym) - (Object) reduce(initial) {|memo, obj| ... } - (Object) reduce {|memo, obj| ... }

Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.

If you specify a block, then for each element in enum the block is passed an accumulator value (memo) and the element. If you specify a symbol instead, then each element in the collection will be passed to the named method of memo. In either case, the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.

If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.

# Sum some numbers
(5..10).reduce(:+)                             #=> 45
# Same using a block and inject
(5..10).inject { |sum, n| sum + n }            #=> 45
# Multiply some numbers
(5..10).reduce(1, :*)                          #=> 151200
# Same using a block
(5..10).inject(1) { |product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo, word|
   memo.length > word.length ? memo : word
end
longest                                        #=> "sheep"

Overloads:

  • - (Object) inject(initial) {|memo, obj| ... }

    Yields:

    • (memo, obj)
  • - (Object) inject {|memo, obj| ... }

    Yields:

    • (memo, obj)
  • - (Object) reduce(initial) {|memo, obj| ... }

    Yields:

    • (memo, obj)
  • - (Object) reduce {|memo, obj| ... }

    Yields:

    • (memo, obj)


635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
# File 'enum.c', line 635

static VALUE
enum_inject(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;
    VALUE init, op;
    rb_block_call_func *iter = inject_i;
    ID id;

    switch (rb_scan_args(argc, argv, "02", &init, &op)) {
      case 0:
	break;
      case 1:
	if (rb_block_given_p()) {
	    break;
	}
	id = rb_check_id(&init);
	op = id ? ID2SYM(id) : init;
	argc = 0;
	init = Qnil;
	iter = inject_op_i;
	break;
      case 2:
	if (rb_block_given_p()) {
	    rb_warning("given block not used");
	}
	id = rb_check_id(&op);
	if (id) op = ID2SYM(id);
	iter = inject_op_i;
	break;
    }
    memo = NEW_MEMO(init, argc, op);
    rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
    return memo->u1.value;
}

- (Object) lazy

Returns a lazy enumerator, whose methods map/collect, flat_map/collect_concat, select/find_all, reject, grep, zip, take, take_while, drop, and drop_while enumerate values only on an as-needed basis. However, if a block is given to zip, values are enumerated immediately.

Example

The following program finds pythagorean triples:

def pythagorean_triples
  (1..Float::INFINITY).lazy.flat_map {|z|
    (1..z).flat_map {|x|
      (x..z).select {|y|
        x**2 + y**2 == z**2
      }.map {|y|
        [x, y, z]
      }
    }
  }
end
# show first ten pythagorean triples
p pythagorean_triples.take(10).force # take is lazy, so force is needed
p pythagorean_triples.first(10)      # first is eager
# show pythagorean triples less than 100
p pythagorean_triples.take_while { |*, z| z < 100 }.force


1451
1452
1453
1454
1455
1456
1457
1458
# File 'enumerator.c', line 1451

static VALUE
enumerable_lazy(VALUE obj)
{
    VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size);
    /* Qfalse indicates that the Enumerator::Lazy has no method name */
    rb_ivar_set(result, id_method, Qfalse);
    return result;
}

- (Array) collect {|obj| ... } - (Array) map {|obj| ... } - (Object) collect - (Object) map

Returns a new array with the results of running block once for every element in enum.

If no block is given, an enumerator is returned instead.

(1..4).map { |i| i*i }      #=> [1, 4, 9, 16]
(1..4).collect { "cat"  }   #=> ["cat", "cat", "cat", "cat"]

Overloads:

  • - (Array) collect {|obj| ... }

    Yields:

    • (obj)
  • - (Array) map {|obj| ... }

    Yields:

    • (obj)


428
429
430
431
432
433
434
435
436
437
438
439
# File 'enum.c', line 428

static VALUE
enum_collect(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, collect_i, ary);

    return ary;
}

- (Object) max - (Object) max {|a, b| ... }

Returns the object in enum with the maximum value. The first form assumes all objects implement Comparable; the second uses the block to return a <=> b.

a = %w(albatross dog horse)
a.max                                   #=> "horse"
a.max { |a, b| a.length <=> b.length }  #=> "albatross"

Overloads:

  • - (Object) max {|a, b| ... }

    Yields:

    • (a, b)


1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
# File 'enum.c', line 1296

static VALUE
enum_max(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qundef, 0, 0);
    VALUE result;

    if (rb_block_given_p()) {
	rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)memo);
    }
    else {
	rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)memo);
    }
    result = memo->u1.value;
    if (result == Qundef) return Qnil;
    return result;
}

- (Object) max_by {|obj| ... } - (Object) max_by

Returns the object in enum that gives the maximum value from the given block.

If no block is given, an enumerator is returned instead.

a = %w(albatross dog horse)
a.max_by { |x| x.length }   #=> "albatross"

Overloads:

  • - (Object) max_by {|obj| ... }

    Yields:

    • (obj)


1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
# File 'enum.c', line 1546

static VALUE
enum_max_by(VALUE obj)
{
    NODE *memo;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    memo = NEW_MEMO(Qundef, Qnil, 0);
    rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
    return memo->u2.value;
}

- (Boolean) include?(obj) - (Boolean) member?(obj)

Returns true if any member of enum equals obj. Equality is tested using ==.

IO.constants.include? :SEEK_SET          #=> true
IO.constants.include? :SEEK_NO_FURTHER   #=> false


1689
1690
1691
1692
1693
1694
1695
1696
# File 'enum.c', line 1689

static VALUE
enum_member(VALUE obj, VALUE val)
{
    NODE *memo = NEW_MEMO(val, Qfalse, 0);

    rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
    return memo->u2.value;
}

- (Object) min - (Object) min {|a, b| ... }

Returns the object in enum with the minimum value. The first form assumes all objects implement Comparable; the second uses the block to return a <=> b.

a = %w(albatross dog horse)
a.min                                   #=> "albatross"
a.min { |a, b| a.length <=> b.length }  #=> "dog"

Overloads:

  • - (Object) min {|a, b| ... }

    Yields:

    • (a, b)


1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
# File 'enum.c', line 1225

static VALUE
enum_min(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qundef, 0, 0);
    VALUE result;

    if (rb_block_given_p()) {
	rb_block_call(obj, id_each, 0, 0, min_ii, (VALUE)memo);
    }
    else {
	rb_block_call(obj, id_each, 0, 0, min_i, (VALUE)memo);
    }
    result = memo->u1.value;
    if (result == Qundef) return Qnil;
    return result;
}

- (Object) min_by {|obj| ... } - (Object) min_by

Returns the object in enum that gives the minimum value from the given block.

If no block is given, an enumerator is returned instead.

a = %w(albatross dog horse)
a.min_by { |x| x.length }   #=> "dog"

Overloads:

  • - (Object) min_by {|obj| ... }

    Yields:

    • (obj)


1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
# File 'enum.c', line 1500

static VALUE
enum_min_by(VALUE obj)
{
    NODE *memo;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    memo = NEW_MEMO(Qundef, Qnil, 0);
    rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
    return memo->u2.value;
}

- (Array) minmax - (Array) minmax {|a, b| ... }

Returns two elements array which contains the minimum and the maximum value in the enumerable. The first form assumes all objects implement Comparable; the second uses the block to return a <=> b.

a = %w(albatross dog horse)
a.minmax                                  #=> ["albatross", "horse"]
a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"]

Overloads:

  • - (Array) minmax {|a, b| ... }

    Yields:

    • (a, b)


1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
# File 'enum.c', line 1440

static VALUE
enum_minmax(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qundef, Qundef, Qundef);
    struct minmax_t *m = (struct minmax_t *)&memo->u1.value;
    VALUE ary = rb_ary_new3(2, Qnil, Qnil);

    m->min = Qundef;
    m->last = Qundef;
    if (rb_block_given_p()) {
	rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)memo);
	if (m->last != Qundef)
	    minmax_ii_update(m->last, m->last, m);
    }
    else {
	rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)memo);
	if (m->last != Qundef)
	    minmax_i_update(m->last, m->last, m);
    }
    if (m->min != Qundef) {
	rb_ary_store(ary, 0, m->min);
	rb_ary_store(ary, 1, m->max);
    }
    return ary;
}

- (Array) minmax_by {|obj| ... } - (Object) minmax_by

Returns a two element array containing the objects in enum that correspond to the minimum and maximum values respectively from the given block.

If no block is given, an enumerator is returned instead.

a = %w(albatross dog horse)
a.minmax_by { |x| x.length }   #=> ["dog", "albatross"]

Overloads:

  • - (Array) minmax_by {|obj| ... }

    Yields:

    • (obj)


1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
# File 'enum.c', line 1643

static VALUE
enum_minmax_by(VALUE obj)
{
    VALUE memo;
    struct minmax_by_t *m = NEW_MEMO_FOR(struct minmax_by_t, memo);

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    m->min_bv = Qundef;
    m->max_bv = Qundef;
    m->min = Qnil;
    m->max = Qnil;
    m->last_bv = Qundef;
    m->last = Qundef;
    rb_block_call(obj, id_each, 0, 0, minmax_by_i, memo);
    if (m->last_bv != Qundef)
        minmax_by_i_update(m->last_bv, m->last_bv, m->last, m->last, m);
    m = MEMO_FOR(struct minmax_by_t, memo);
    return rb_assoc_new(m->min, m->max);
}

- (Boolean) none? {|obj| ... }

Passes each element of the collection to the given block. The method returns true if the block never returns true for all elements. If the block is not given, none? will return true only if none of the collection members is true.

%w{ant bear cat}.none? { |word| word.length == 5 } #=> true
%w{ant bear cat}.none? { |word| word.length >= 4 } #=> false
[].none?                                           #=> true
[nil].none?                                        #=> true
[nil, false].none?                                 #=> true

Yields:

  • (obj)


1162
1163
1164
1165
1166
1167
1168
# File 'enum.c', line 1162

static VALUE
enum_none(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qtrue, 0, 0);
    rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo);
    return memo->u1.value;
}

- (Boolean) one? {|obj| ... }

Passes each element of the collection to the given block. The method returns true if the block returns true exactly once. If the block is not given, one? will return true only if exactly one of the collection members is true.

%w{ant bear cat}.one? { |word| word.length == 4 }  #=> true
%w{ant bear cat}.one? { |word| word.length > 4 }   #=> false
%w{ant bear cat}.one? { |word| word.length < 4 }   #=> false
[ nil, true, 99 ].one?                             #=> false
[ nil, true, false ].one?                          #=> true

Yields:

  • (obj)


1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
# File 'enum.c', line 1126

static VALUE
enum_one(VALUE obj)
{
    NODE *memo = NEW_MEMO(Qundef, 0, 0);
    VALUE result;

    rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo);
    result = memo->u1.value;
    if (result == Qundef) return Qfalse;
    return result;
}

- (Array) partition {|obj| ... } - (Object) partition

Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.

If no block is given, an enumerator is returned instead.

(1..6).partition { |v| v.even? }  #=> [[2, 4, 6], [1, 3, 5]]

Overloads:

  • - (Array) partition {|obj| ... }

    Yields:

    • (obj)


702
703
704
705
706
707
708
709
710
711
712
713
# File 'enum.c', line 702

static VALUE
enum_partition(VALUE obj)
{
    NODE *memo;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    memo = NEW_MEMO(rb_ary_new(), rb_ary_new(), 0);
    rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);

    return rb_assoc_new(memo->u1.value, memo->u2.value);
}

- (Object) inject(initial, sym) - (Object) inject(sym) - (Object) inject(initial) {|memo, obj| ... } - (Object) inject {|memo, obj| ... } - (Object) reduce(initial, sym) - (Object) reduce(sym) - (Object) reduce(initial) {|memo, obj| ... } - (Object) reduce {|memo, obj| ... }

Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.

If you specify a block, then for each element in enum the block is passed an accumulator value (memo) and the element. If you specify a symbol instead, then each element in the collection will be passed to the named method of memo. In either case, the result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method.

If you do not explicitly specify an initial value for memo, then the first element of collection is used as the initial value of memo.

# Sum some numbers
(5..10).reduce(:+)                             #=> 45
# Same using a block and inject
(5..10).inject { |sum, n| sum + n }            #=> 45
# Multiply some numbers
(5..10).reduce(1, :*)                          #=> 151200
# Same using a block
(5..10).inject(1) { |product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo, word|
   memo.length > word.length ? memo : word
end
longest                                        #=> "sheep"

Overloads:

  • - (Object) inject(initial) {|memo, obj| ... }

    Yields:

    • (memo, obj)
  • - (Object) inject {|memo, obj| ... }

    Yields:

    • (memo, obj)
  • - (Object) reduce(initial) {|memo, obj| ... }

    Yields:

    • (memo, obj)
  • - (Object) reduce {|memo, obj| ... }

    Yields:

    • (memo, obj)


635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
# File 'enum.c', line 635

static VALUE
enum_inject(int argc, VALUE *argv, VALUE obj)
{
    NODE *memo;
    VALUE init, op;
    rb_block_call_func *iter = inject_i;
    ID id;

    switch (rb_scan_args(argc, argv, "02", &init, &op)) {
      case 0:
	break;
      case 1:
	if (rb_block_given_p()) {
	    break;
	}
	id = rb_check_id(&init);
	op = id ? ID2SYM(id) : init;
	argc = 0;
	init = Qnil;
	iter = inject_op_i;
	break;
      case 2:
	if (rb_block_given_p()) {
	    rb_warning("given block not used");
	}
	id = rb_check_id(&op);
	if (id) op = ID2SYM(id);
	iter = inject_op_i;
	break;
    }
    memo = NEW_MEMO(init, argc, op);
    rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
    return memo->u1.value;
}

- (Array) reject {|obj| ... } - (Object) reject

Returns an array for all elements of enum for which the given block returns false.

If no block is given, an Enumerator is returned instead.

(1..10).reject { |i|  i % 3 == 0 }   #=> [1, 2, 4, 5, 7, 8, 10]

[1, 2, 3, 4, 5].reject { |num| num.even? } #=> [1, 3, 5]

See also Enumerable#find_all.

Overloads:

  • - (Array) reject {|obj| ... }

    Yields:

    • (obj)


381
382
383
384
385
386
387
388
389
390
391
392
# File 'enum.c', line 381

static VALUE
enum_reject(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, reject_i, ary);

    return ary;
}

- (Enumerator) reverse_each(*args) {|item| ... } - (Object) reverse_each(*args)

Builds a temporary array and traverses that array in reverse order.

If no block is given, an enumerator is returned instead.

  (1..3).reverse_each { |v| p v }

produces:

  3
  2
  1

Overloads:

  • - (Enumerator) reverse_each(*args) {|item| ... }

    Yields:

    • (item)


1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
# File 'enum.c', line 1756

static VALUE
enum_reverse_each(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary;
    long i;

    RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);

    ary = enum_to_a(argc, argv, obj);

    for (i = RARRAY_LEN(ary); --i >= 0; ) {
	rb_yield(RARRAY_AREF(ary, i));
    }

    return obj;
}

- (Array) find_all {|obj| ... } - (Array) select {|obj| ... } - (Object) find_all - (Object) select

Returns an array containing all elements of enum for which the given block returns a true value.

If no block is given, an Enumerator is returned instead.

(1..10).find_all { |i|  i % 3 == 0 }   #=> [3, 6, 9]

[1,2,3,4,5].select { |num|  num.even?  }   #=> [2, 4]

See also Enumerable#reject.

Overloads:

  • - (Array) find_all {|obj| ... }

    Yields:

    • (obj)
  • - (Array) select {|obj| ... }

    Yields:

    • (obj)


340
341
342
343
344
345
346
347
348
349
350
351
# File 'enum.c', line 340

static VALUE
enum_find_all(VALUE obj)
{
    VALUE ary;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, find_all_i, ary);

    return ary;
}

- (Object) slice_before(pattern) - (Object) slice_before {|elt| ... } - (Object) slice_before(initial_state) {|elt, state| ... }

Creates an enumerator for each chunked elements. The beginnings of chunks are defined by pattern and the block.

If pattern === elt returns true or the block returns true for the element, the element is beginning of a chunk.

The === and block is called from the first element to the last element of enum. The result for the first element is ignored.

The result enumerator yields the chunked elements as an array. So each method can be called as follows:

enum.slice_before(pattern).each { |ary| ... }
enum.slice_before { |elt| bool }.each { |ary| ... }
enum.slice_before(initial_state) { |elt, state| bool }.each { |ary| ... }

Other methods of the Enumerator class and Enumerable module, such as map, etc., are also usable.

For example, iteration over ChangeLog entries can be implemented as follows:

# iterate over ChangeLog entries.
open("ChangeLog") { |f|
  f.slice_before(/\A\S/).each { |e| pp e }
}

# same as above.  block is used instead of pattern argument.
open("ChangeLog") { |f|
  f.slice_before { |line| /\A\S/ === line }.each { |e| pp e }
}

“svn proplist -R” produces multiline output for each file. They can be chunked as follows:

IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) { |f|
  f.lines.slice_before(/\AProp/).each { |lines| p lines }
}
#=> ["Properties on '.':\n", "  svn:ignore\n", "  svk:merge\n"]
#   ["Properties on 'goruby.c':\n", "  svn:eol-style\n"]
#   ["Properties on 'complex.c':\n", "  svn:mime-type\n", "  svn:eol-style\n"]
#   ["Properties on 'regparse.c':\n", "  svn:eol-style\n"]
#   ...

If the block needs to maintain state over multiple elements, local variables can be used. For example, three or more consecutive increasing numbers can be squashed as follows:

a = [0, 2, 3, 4, 6, 7, 9]
prev = a[0]
p a.slice_before { |e|
  prev, prev2 = e, prev
  prev2 + 1 != e
}.map { |es|
  es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
}.join(",")
#=> "0,2-4,6,7,9"

However local variables are not appropriate to maintain state if the result enumerator is used twice or more. In such a case, the last state of the 1st each is used in the 2nd each. The initial_state argument can be used to avoid this problem. If non-nil value is given as initial_state, it is duplicated for each each method invocation of the enumerator. The duplicated object is passed to 2nd argument of the block for slice_before method.

# Word wrapping.  This assumes all characters have same width.
def wordwrap(words, maxwidth)
  # if cols is a local variable, 2nd "each" may start with non-zero cols.
  words.slice_before(cols: 0) { |w, h|
    h[:cols] += 1 if h[:cols] != 0
    h[:cols] += w.length
    if maxwidth < h[:cols]
      h[:cols] = w.length
      true
    else
      false
    end
  }
end
text = (1..20).to_a.join(" ")
enum = wordwrap(text.split(/\s+/), 10)
puts "-"*10
enum.each { |ws| puts ws.join(" ") }
puts "-"*10
#=> ----------
#   1 2 3 4 5
#   6 7 8 9 10
#   11 12 13
#   14 15 16
#   17 18 19
#   20
#   ----------

mbox contains series of mails which start with Unix From line. So each mail can be extracted by slice before Unix From line.

# parse mbox
open("mbox") { |f|
  f.slice_before { |line|
    line.start_with? "From "
  }.each { |mail|
    unix_from = mail.shift
    i = mail.index("\n")
    header = mail[0...i]
    body = mail[(i+1)..-1]
    body.pop if body.last == "\n"
    fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a
    p unix_from
    pp fields
    pp body
  }
}

# split mails in mbox (slice before Unix From line after an empty line)
open("mbox") { |f|
  f.slice_before(emp: true) { |line, h|
    prevemp = h[:emp]
    h[:emp] = line == "\n"
    prevemp && line.start_with?("From ")
  }.each { |mail|
    mail.pop if mail.last == "\n"
    pp mail
  }
}

Overloads:

  • - (Object) slice_before {|elt| ... }

    Yields:

    • (elt)
  • - (Object) slice_before(initial_state) {|elt, state| ... }

    Yields:

    • (elt, state)


2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
# File 'enum.c', line 2758

static VALUE
enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
{
    VALUE enumerator;

    if (rb_block_given_p()) {
        VALUE initial_state;
        rb_scan_args(argc, argv, "01", &initial_state);
        enumerator = rb_obj_alloc(rb_cEnumerator);
        rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pred"), rb_block_proc());
        rb_ivar_set(enumerator, rb_intern("slicebefore_initial_state"), initial_state);
    }
    else {
        VALUE sep_pat;
        rb_scan_args(argc, argv, "1", &sep_pat);
        enumerator = rb_obj_alloc(rb_cEnumerator);
        rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pat"), sep_pat);
    }
    rb_ivar_set(enumerator, rb_intern("slicebefore_enumerable"), enumerable);
    rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator);
    return enumerator;
}

- (Array) sort - (Array) sort {|a, b| ... }

Returns an array containing the items in enum sorted, either according to their own <=> method, or by using the results of the supplied block. The block should return -1, 0, or +1 depending on the comparison between a and b. As of Ruby 1.8, the method Enumerable#sort_by implements a built-in Schwartzian Transform, useful when key computation or comparison is expensive.

%w(rhea kea flea).sort          #=> ["flea", "kea", "rhea"]
(1..10).sort { |a, b| b <=> a }  #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Overloads:

  • - (Array) sort {|a, b| ... }

    Yields:

    • (a, b)


827
828
829
830
831
# File 'enum.c', line 827

static VALUE
enum_sort(VALUE obj)
{
    return rb_ary_sort(enum_to_a(0, 0, obj));
}

- (Array) sort_by {|obj| ... } - (Object) sort_by

Sorts enum using a set of keys generated by mapping the values in enum through the given block.

If no block is given, an enumerator is returned instead.

%w{apple pear fig}.sort_by { |word| word.length}
              #=> ["fig", "pear", "apple"]

The current implementation of sort_by generates an array of tuples containing the original collection element and the mapped value. This makes sort_by fairly expensive when the keysets are simple.

require 'benchmark'

a = (1..100000).map { rand(100000) }

Benchmark.bm(10) do |b|
  b.report("Sort")    { a.sort }
  b.report("Sort by") { a.sort_by { |a| a } }
end

produces:

user     system      total        real
Sort        0.180000   0.000000   0.180000 (  0.175469)
Sort by     1.980000   0.040000   2.020000 (  2.013586)

However, consider the case where comparing the keys is a non-trivial operation. The following code sorts some files on modification time using the basic sort method.

files = Dir["*"]
sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
sorted   #=> ["mon", "tues", "wed", "thurs"]

This sort is inefficient: it generates two new File objects during every comparison. A slightly better technique is to use the Kernel#test method to generate the modification times directly.

files = Dir["*"]
sorted = files.sort { |a, b|
  test(?M, a) <=> test(?M, b)
}
sorted   #=> ["mon", "tues", "wed", "thurs"]

This still generates many unnecessary Time objects. A more efficient technique is to cache the sort keys (modification times in this case) before the sort. Perl users often call this approach a Schwartzian Transform, after Randal Schwartz. We construct a temporary array, where each element is an array containing our sort key along with the filename. We sort this array, and then extract the filename from the result.

sorted = Dir["*"].collect { |f|
   [test(?M, f), f]
}.sort.collect { |f| f[1] }
sorted   #=> ["mon", "tues", "wed", "thurs"]

This is exactly what sort_by does internally.

sorted = Dir["*"].sort_by { |f| test(?M, f) }
sorted   #=> ["mon", "tues", "wed", "thurs"]

Overloads:

  • - (Array) sort_by {|obj| ... }

    Yields:

    • (obj)


956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
# File 'enum.c', line 956

static VALUE
enum_sort_by(VALUE obj)
{
    VALUE ary, buf;
    NODE *memo;
    long i;
    struct sort_by_data *data;

    RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

    if (RB_TYPE_P(obj, T_ARRAY) && RARRAY_LEN(obj) <= LONG_MAX/2) {
	ary = rb_ary_new2(RARRAY_LEN(obj)*2);
    }
    else {
	ary = rb_ary_new();
    }
    RBASIC_CLEAR_CLASS(ary);
    buf = rb_ary_tmp_new(SORT_BY_BUFSIZE*2);
    rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
    memo = NEW_MEMO(0, 0, 0);
    OBJ_INFECT(memo, obj);
    data = (struct sort_by_data *)&memo->u1;
    data->ary = ary;
    data->buf = buf;
    data->n = 0;
    rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
    ary = data->ary;
    buf = data->buf;
    if (data->n) {
	rb_ary_resize(buf, data->n*2);
	rb_ary_concat(ary, buf);
    }
    if (RARRAY_LEN(ary) > 2) {
	RARRAY_PTR_USE(ary, ptr,
		      ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
				 sort_by_cmp, (void *)ary));
    }
    if (RBASIC(ary)->klass) {
	rb_raise(rb_eRuntimeError, "sort_by reentered");
    }
    for (i=1; i<RARRAY_LEN(ary); i+=2) {
	RARRAY_ASET(ary, i/2, RARRAY_AREF(ary, i));
    }
    rb_ary_resize(ary, RARRAY_LEN(ary)/2);
    RBASIC_SET_CLASS_RAW(ary, rb_cArray);
    OBJ_INFECT(ary, memo);

    return ary;
}

- (Array) take(n)

Returns first n elements from enum.

a = [1, 2, 3, 4, 5, 0]
a.take(3)             #=> [1, 2, 3]


2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
# File 'enum.c', line 2146

static VALUE
enum_take(VALUE obj, VALUE n)
{
    NODE *memo;
    VALUE result;
    long len = NUM2LONG(n);

    if (len < 0) {
	rb_raise(rb_eArgError, "attempt to take negative size");
    }

    if (len == 0) return rb_ary_new2(0);
    result = rb_ary_new2(len);
    memo = NEW_MEMO(result, 0, len);
    rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
    return result;
}

- (Array) take_while {|arr| ... } - (Object) take_while

Passes elements to the block until the block returns nil or false, then stops iterating and returns an array of all prior elements.

If no block is given, an enumerator is returned instead.

a = [1, 2, 3, 4, 5, 0]
a.take_while { |i| i < 3 }   #=> [1, 2]

Overloads:

  • - (Array) take_while {|arr| ... }

    Yields:

    • (arr)


2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
# File 'enum.c', line 2188

static VALUE
enum_take_while(VALUE obj)
{
    VALUE ary;

    RETURN_ENUMERATOR(obj, 0, 0);
    ary = rb_ary_new();
    rb_block_call(obj, id_each, 0, 0, take_while_i, ary);
    return ary;
}

- (Array) to_a(*args) - (Array) entries(*args)

Returns an array containing the items in enum.

(1..7).to_a                       #=> [1, 2, 3, 4, 5, 6, 7]
{ 'a'=>1, 'b'=>2, 'c'=>3 }.to_a   #=> [["a", 1], ["b", 2], ["c", 3]]

require 'prime'
Prime.entries 10                  #=> [2, 3, 5, 7]


501
502
503
504
505
506
507
508
509
510
# File 'enum.c', line 501

static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary = rb_ary_new();

    rb_block_call(obj, id_each, argc, argv, collect_all, ary);
    OBJ_INFECT(ary, obj);

    return ary;
}

- (Hash) to_h(*args)

Returns the result of interpreting enum as a list of [key, value] pairs.

%i[hello world].each_with_index.to_h
  # => {:hello => 0, :world => 1}


542
543
544
545
546
547
548
549
# File 'enum.c', line 542

static VALUE
enum_to_h(int argc, VALUE *argv, VALUE obj)
{
    VALUE hash = rb_hash_new();
    rb_block_call(obj, id_each, argc, argv, enum_to_h_i, hash);
    OBJ_INFECT(hash, obj);
    return hash;
}

- (Object) zip(arg, ...) - (nil) zip(arg, ...) {|arr| ... }

Takes one element from enum and merges corresponding elements from each args. This generates a sequence of n-element arrays, where n is one more than the count of arguments. The length of the resulting sequence will be enum#size. If the size of any argument is less than enum#size, nil values are supplied. If a block is given, it is invoked for each output array, otherwise an array of arrays is returned.

a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]

[1, 2, 3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
[1, 2].zip(a, b)         #=> [[1, 4, 7], [2, 5, 8]]
a.zip([1, 2], [8])       #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]

Overloads:

  • - (nil) zip(arg, ...) {|arr| ... }

    Yields:

    • (arr)


2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
# File 'enum.c', line 2087

static VALUE
enum_zip(int argc, VALUE *argv, VALUE obj)
{
    int i;
    ID conv;
    NODE *memo;
    VALUE result = Qnil;
    VALUE args = rb_ary_new4(argc, argv);
    int allary = TRUE;

    argv = RARRAY_PTR(args);
    for (i=0; i<argc; i++) {
	VALUE ary = rb_check_array_type(argv[i]);
	if (NIL_P(ary)) {
	    allary = FALSE;
	    break;
	}
	argv[i] = ary;
    }
    if (!allary) {
	CONST_ID(conv, "to_enum");
	for (i=0; i<argc; i++) {
	    if (!rb_respond_to(argv[i], id_each)) {
                rb_raise(rb_eTypeError, "wrong argument type %s (must respond to :each)",
                    rb_obj_classname(argv[i]));
            }
	    argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
	}
    }
    if (!rb_block_given_p()) {
	result = rb_ary_new();
    }
    /* use NODE_DOT2 as memo(v, v, -) */
    memo = rb_node_newnode(NODE_DOT2, result, args, 0);
    rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);

    return result;
}