modul Enumerable
Was gibt es hier
Das Modul Enumerable stellt Methoden bereit, die für eine Sammlungs-Klasse nützlich sind für
Methoden zum Abfragen
Diese Methoden geben Informationen über die Enumerable zurück, die sich von den Elementen selbst unterscheiden
-
member?(alias fürinclude?): Gibttruezurück, wennself == object, andernfallsfalse. -
all?: Gibttruezurück, wenn alle Elemente eine bestimmte Bedingung erfüllen; andernfallsfalse. -
any?: Gibttruezurück, wenn irgendein Element eine bestimmte Bedingung erfüllt; andernfallsfalse. -
none?: Gibttruezurück, wenn kein Element eine bestimmte Bedingung erfüllt; andernfallsfalse. -
one?: Gibttruezurück, wenn genau ein Element eine bestimmte Bedingung erfüllt; andernfallsfalse. -
count: Gibt die Anzahl der Elemente zurück, basierend auf einem Argument oder einer Block-Bedingung, falls angegeben. -
tally: Gibt eine neueHashzurück, die die Häufigkeiten jedes Elements enthält.
Methoden zum Abrufen
Diese Methoden geben Einträge aus der Enumerable zurück, ohne sie zu verändern
Führende, nachfolgende oder alle Elemente:
-
first: Gibt das erste Element oder führende Elemente zurück. -
take: Gibt eine angegebene Anzahl von führenden Elementen zurück. -
drop: Gibt eine angegebene Anzahl von nachfolgenden Elementen zurück. -
take_while: Gibt führende Elemente zurück, wie durch den angegebenen Block bestimmt. -
drop_while: Gibt nachfolgende Elemente zurück, wie durch den angegebenen Block bestimmt.
Elemente mit minimalem und maximalem Wert:
-
min: Gibt die Elemente mit den kleinsten Werten unter den Elementen zurück, bestimmt durch <=> oder einen gegebenen Block. -
max: Gibt die Elemente mit den größten Werten unter den Elementen zurück, bestimmt durch <=> oder einen gegebenen Block. -
minmax: Gibt ein 2-elementigesArrayzurück, das die kleinsten und größten Elemente enthält. -
min_by: Gibt das kleinste Element zurück, bestimmt durch den gegebenen Block. -
max_by: Gibt das größte Element zurück, bestimmt durch den gegebenen Block. -
minmax_by: Gibt die kleinsten und größten Elemente zurück, bestimmt durch den gegebenen Block.
Gruppen, Slices und Partitionen:
-
group_by: Gibt eineHashzurück, die die Elemente in Gruppen aufteilt. -
partition: Gibt Elemente zurück, die in zwei neue Arrays partitioniert sind, bestimmt durch den gegebenen Block. -
slice_after: Gibt einen neuenEnumeratorzurück, dessen Einträge eine Partition vonselfsind, basierend auf einem gegebenenobjectoder einem gegebenen Block. -
slice_before: Gibt einen neuenEnumeratorzurück, dessen Einträge eine Partition vonselfsind, basierend auf einem gegebenenobjectoder einem gegebenen Block. -
slice_when: Gibt einen neuenEnumeratorzurück, dessen Einträge eine Partition vonselfsind, basierend auf dem gegebenen Block. -
chunk: Gibt Elemente zurück, die in Chunks organisiert sind, wie durch den gegebenen Block bestimmt. -
chunk_while: Gibt Elemente zurück, die in Chunks organisiert sind, wie durch den gegebenen Block bestimmt.
Methoden zur Suche und Filterung
Diese Methoden geben Elemente zurück, die eine bestimmte Bedingung erfüllen
-
find(alias fürdetect): Gibt ein durch den Block ausgewähltes Element zurück. -
find_all(alias fürfilter,select): Gibt durch den Block ausgewählte Elemente zurück. -
find_index: Gibt den Index eines durch ein gegebenes Objekt oder einen Block ausgewählten Elements zurück. -
reject: Gibt Elemente zurück, die nicht vom Block abgelehnt wurden. -
uniq: Gibt Elemente zurück, die keine Duplikate sind.
Methoden zur Sortierung
Diese Methoden geben Elemente in sortierter Reihenfolge zurück
-
sort: Gibt die Elemente zurück, sortiert nach <=> oder dem gegebenen Block. -
sort_by: Gibt die Elemente zurück, sortiert nach dem gegebenen Block.
Methoden zur Iteration
-
each_entry: Ruft den Block mit jedem aufeinanderfolgenden Element auf (etwas anders als each). -
each_with_index: Ruft den Block mit jedem aufeinanderfolgenden Element und seinem Index auf. -
each_with_object: Ruft den Block mit jedem aufeinanderfolgenden Element und einem gegebenen Objekt auf. -
each_slice: Ruft den Block mit aufeinanderfolgenden, nicht überlappenden Slices auf. -
each_cons: Ruft den Block mit aufeinanderfolgenden, überlappenden Slices auf. (unterschiedlich voneach_slice). -
reverse_each: Ruft den Block mit jedem aufeinanderfolgenden Element in umgekehrter Reihenfolge auf.
Andere Methoden
-
collect(alias fürmap): Gibt Objekte zurück, die vom Block zurückgegeben werden. -
filter_map: Gibt wahrheitsfähige Objekte zurück, die vom Block zurückgegeben werden. -
flat_map(alias fürcollect_concat): Gibt abgeflachte Objekte zurück, die vom Block zurückgegeben werden. -
grep: Gibt Elemente zurück, die von einem gegebenen Objekt oder von einem Block zurückgegebenen Objekten ausgewählt werden. -
grep_v: Gibt Elemente zurück, die nicht von einem gegebenen Objekt oder von einem Block zurückgegebenen Objekten ausgewählt werden. -
inject(alias fürreduce): Gibt das Objekt zurück, das durch Kombination aller Elemente gebildet wird. -
sum: Gibt die Summe der Elemente zurück, unter Verwendung der Methode+. -
zip: Kombiniert jedes Element mit Elementen aus anderen Enumerable; gibt die n-Tupel zurück oder ruft den Block mit jedem auf. -
cycle: Ruft den Block mit jedem Element auf und wiederholt den Vorgang.
Verwendung
Um das Modul Enumerable in einer Sammlungs-Klasse zu verwenden
-
Integrieren Sie es
include Enumerable
-
Implementieren Sie die Methode each, die aufeinanderfolgende Elemente der Sammlung ergeben muss. Die Methode wird von fast jeder Enumerable-Methode aufgerufen.
Beispiel
class Foo include Enumerable def each yield 1 yield 1, 2 yield end end Foo.new.each_entry{ |element| p element }
Ausgabe
1 [1, 2] nil
Enumerable in Ruby-Klassen
Diese Ruby Core-Klassen enthalten (oder erweitern) Enumerable
Diese Ruby Standardbibliothek-Klassen enthalten Enumerable
-
CSV
-
CSV::Table
-
CSV::Row
-
Set
Praktisch alle Methoden in Enumerable rufen die Methode each in der inkludierenden Klasse auf
-
Hash#eachergibt das nächste Schlüssel-Wert-Paar als 2-elementigesArray. -
Struct#eachergibt das nächste Namen-Wert-Paar als 2-elementigesArray. -
Für die anderen oben genannten Klassen ergibt each das nächste Objekt aus der Sammlung.
Über die Beispiele
Die Beispielcode-Schnipsel für die Enumerable-Methoden
-
Zeigen immer die Verwendung einer oder mehrerer Array-ähnlicher Klassen (oft
Arrayselbst). -
Manchmal wird die Verwendung einer Hash-ähnlichen Klasse gezeigt. Bei einigen Methoden wäre die Verwendung jedoch nicht sinnvoll und wird daher nicht gezeigt. Beispiel:
tallywürde genau einen von jedemHash-Eintrag finden.
Erweiterte Methoden
Eine Enumerable-Klasse kann erweiterte Methoden definieren. Dieser Abschnitt beschreibt das Standardverhalten von Erweiterungsmethoden zu Referenzzwecken.
size
Enumerator hat eine size-Methode. Sie verwendet das der Methode Enumerator.new übergebene Funktionsargument size.
e = Enumerator.new(-> { 3 }) {|y| p y; y.yield :a; y.yield :b; y.yield :c; :z } p e.size #=> 3 p e.next #=> :a p e.next #=> :b p e.next #=> :c begin e.next rescue StopIteration p $!.result #=> :z end
Das Ergebnis der size-Funktion sollte die Anzahl der Iterationen darstellen (d. h. wie oft Enumerator::Yielder#yield aufgerufen wird). Im obigen Beispiel ruft der Block yield dreimal auf, und die size-Funktion, +-> { 3 }+, gibt entsprechend 3 zurück. Das Ergebnis der size-Funktion kann eine Ganzzahl, Float::INFINITY oder nil sein. Eine Ganzzahl bedeutet die genaue Anzahl der yield-Aufrufe, wie oben gezeigt. Float::INFINITY zeigt eine unendliche Anzahl von yield-Aufrufen an. nil bedeutet, dass die Anzahl der yield-Aufrufe schwierig oder unmöglich zu bestimmen ist.
Viele Iterationsmethoden geben ein Enumerator-Objekt mit einer entsprechenden size-Funktion zurück, wenn kein Block gegeben ist.
Beispiele
["a", "b", "c"].each.size #=> 3 {a: "x", b: "y", c: "z"}.each.size #=> 3 (0..20).to_a.permutation.size #=> 51090942171709440000 loop.size #=> Float::INFINITY (1..100).drop_while.size #=> nil # size depends on the block's behavior STDIN.each.size #=> nil # cannot be computed without consuming input File.open("/etc/resolv.conf").each.size #=> nil # cannot be computed without reading the file
Das Verhalten von size für Range-basierte Enumeratoren hängt vom Anfangselement ab
-
Wenn das Anfangselement eine
Integerist, gibt die size-Methode eineIntegeroderFloat::INFINITYzurück. -
Wenn das Anfangselement ein Objekt mit einer succ-Methode ist (außer
Integer), gibt sizenilzurück. (Die Berechnung der Größe würde wiederholtes Aufrufen von succ erfordern, was zu langsam sein kann.) -
Wenn das Anfangselement keine succ-Methode hat, löst size eine
TypeErroraus.
Beispiele
(10..42).each.size #=> 33 (10..42.9).each.size #=> 33 (the #end element may be a non-integer numeric) (10..).each.size #=> Float::INFINITY ("a".."z").each.size #=> nil ("a"..).each.size #=> nil (1.0..9.0).each.size # raises TypeError (Float does not have #succ) (..10).each.size # raises TypeError (beginless range has nil as its #begin)
Das Modul Enumerable selbst definiert keine size-Methode. Eine Klasse, die Enumerable enthält, kann ihre eigene size-Methode definieren. Es wird empfohlen, dass eine solche size-Methode mit Enumerator#size konsistent ist.
Array und Hash implementieren size und geben Werte zurück, die mit Enumerator#size konsistent sind. IO und Dir definieren keine size, was ebenfalls konsistent ist, da die size-Funktion des entsprechenden Enumerators nil zurückgibt.
Es ist jedoch nicht zwingend erforderlich, dass die size-Methode einer Klasse mit Enumerator#size übereinstimmt. Beispielsweise gibt File#size die Anzahl der Bytes in der Datei zurück, nicht die Anzahl der Zeilen.
Öffentliche Instanzmethoden
Source
static VALUE
enum_all(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(all);
return memo->v1;
}
Gibt zurück, ob jedes Element eine gegebene Bedingung erfüllt.
Wenn self kein Element hat, wird true zurückgegeben und Argument oder Block werden nicht verwendet.
Ohne Argument und ohne Block wird zurückgegeben, ob jedes Element wahrheitsfähig ist
(1..4).all? # => true %w[a b c d].all? # => true [1, 2, nil].all? # => false ['a','b', false].all? # => false [].all? # => true
Mit dem Argument muster und ohne Block wird zurückgegeben, ob für jedes Element element gilt: muster === element
(1..4).all?(Integer) # => true (1..4).all?(Numeric) # => true (1..4).all?(Float) # => false %w[bar baz bat bam].all?(/ba/) # => true %w[bar baz bat bam].all?(/bar/) # => false %w[bar baz bat bam].all?('ba') # => false {foo: 0, bar: 1, baz: 2}.all?(Array) # => true {foo: 0, bar: 1, baz: 2}.all?(Hash) # => false [].all?(Integer) # => true
Mit einem Block wird zurückgegeben, ob der Block für jedes Element einen wahrheitsfähigen Wert zurückgibt
(1..4).all? {|element| element < 5 } # => true (1..4).all? {|element| element < 4 } # => false {foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 3 } # => true {foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 2 } # => false
Source
static VALUE
enum_any(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(any);
return memo->v1;
}
Gibt zurück, ob irgendein Element eine gegebene Bedingung erfüllt.
Wenn self kein Element hat, wird false zurückgegeben und Argument oder Block werden nicht verwendet.
Ohne Argument und ohne Block wird zurückgegeben, ob irgendein Element wahrheitsfähig ist
(1..4).any? # => true %w[a b c d].any? # => true [1, false, nil].any? # => true [].any? # => false
Mit dem Argument muster und ohne Block wird zurückgegeben, ob für irgendein Element element gilt: muster === element
[nil, false, 0].any?(Integer) # => true [nil, false, 0].any?(Numeric) # => true [nil, false, 0].any?(Float) # => false %w[bar baz bat bam].any?(/m/) # => true %w[bar baz bat bam].any?(/foo/) # => false %w[bar baz bat bam].any?('ba') # => false {foo: 0, bar: 1, baz: 2}.any?(Array) # => true {foo: 0, bar: 1, baz: 2}.any?(Hash) # => false [].any?(Integer) # => false
Mit einem Block wird zurückgegeben, ob der Block für irgendein Element einen wahrheitsfähigen Wert zurückgibt
(1..4).any? {|element| element < 2 } # => true (1..4).any? {|element| element < 1 } # => false {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 1 } # => true {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 0 } # => false
Source
static VALUE
enum_chain(int argc, VALUE *argv, VALUE obj)
{
VALUE enums = rb_ary_new_from_values(1, &obj);
rb_ary_cat(enums, argv, argc);
return new_enum_chain(enums);
}
Gibt ein Enumerator-Objekt zurück, das aus diesem Enumerator und den gegebenen Enumerable-Objekten generiert wird.
e = (1..3).chain([4, 5]) e.to_a #=> [1, 2, 3, 4, 5]
Source
static VALUE
enum_chunk(VALUE enumerable)
{
VALUE enumerator;
RETURN_SIZED_ENUMERATOR(enumerable, 0, 0, enum_size);
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_chunk_enumerable, enumerable);
rb_ivar_set(enumerator, id_chunk_categorize, rb_block_proc());
rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator);
return enumerator;
}
Jedes Element im zurückgegebenen Enumerator ist ein 2-elementiges Array bestehend aus
-
Ein Wert, der vom Block zurückgegeben wird.
-
Ein Array („Chunk“), das das Element enthält, für das dieser Wert zurückgegeben wurde, und alle folgenden Elemente, für die der Block denselben Wert zurückgegeben hat
So dass
-
Jeder Block-Rückgabewert, der sich von seinem Vorgänger unterscheidet, beginnt einen neuen Chunk.
-
Jeder Block-Rückgabewert, der mit seinem Vorgänger übereinstimmt, setzt denselben Chunk fort.
Beispiel
e = (0..10).chunk {|i| (i / 3).floor } # => #<Enumerator: ...> # The enumerator elements. e.next # => [0, [0, 1, 2]] e.next # => [1, [3, 4, 5]] e.next # => [2, [6, 7, 8]] e.next # => [3, [9, 10]]
Die Methode chunk ist besonders nützlich für eine Enumerable, die bereits sortiert ist. Dieses Beispiel zählt Wörter für jeden Anfangsbuchstaben in einem großen Array von Wörtern
# Get sorted words from a web page. url = 'https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt' words = URI::open(url).readlines # Make chunks, one for each letter. e = words.chunk {|word| word.upcase[0] } # => #<Enumerator: ...> # Display 'A' through 'F'. e.each {|c, words| p [c, words.length]; break if c == 'F' }
Ausgabe
["A", 17096] ["B", 11070] ["C", 19901] ["D", 10896] ["E", 8736] ["F", 6860]
Sie können das spezielle Symbol :_alone verwenden, um ein Element in seinen eigenen separaten Chunk zu zwingen
a = [0, 0, 1, 1] e = a.chunk{|i| i.even? ? :_alone : true } e.to_a # => [[:_alone, [0]], [:_alone, [0]], [true, [1, 1]]]
Zum Beispiel können Sie jede Zeile, die eine URL enthält, in ihren eigenen Chunk setzen
pattern = /http/ open(filename) { |f| f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines| pp lines } }
Sie können das spezielle Symbol :_separator oder nil verwenden, um ein Element zu erzwingen, das ignoriert wird (nicht in einen Chunk aufgenommen)
a = [0, 0, -1, 1, 1] e = a.chunk{|i| i < 0 ? :_separator : true } e.to_a # => [[true, [0, 0]], [true, [1, 1]]]
Beachten Sie, dass der Trennzeichen den Chunk beendet
a = [0, 0, -1, 1, -1, 1] e = a.chunk{|i| i < 0 ? :_separator : true } e.to_a # => [[true, [0, 0]], [true, [1]], [true, [1]]]
Zum Beispiel kann die Hyphen-Sequenz in svn log wie folgt eliminiert werden
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"] # ...
Absätze, die durch leere Zeilen getrennt sind, können wie folgt geparst werden
File.foreach("README").chunk { |line| /\A\s*\z/ !~ line || nil }.each { |_, lines| pp lines }
Source
static VALUE
enum_chunk_while(VALUE enumerable)
{
VALUE enumerator;
VALUE pred;
pred = rb_block_proc();
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicewhen_enum, enumerable);
rb_ivar_set(enumerator, id_slicewhen_pred, pred);
rb_ivar_set(enumerator, id_slicewhen_inverted, Qtrue);
rb_block_call(enumerator, idInitialize, 0, 0, slicewhen_i, enumerator);
return enumerator;
}
Erstellt einen Enumerator für jedes gechunkte Element. Die Anfänge von Chunks werden durch den Block definiert.
Diese Methode teilt Chunks anhand von benachbarten Elementen, elt_before und elt_after, im empfangenden Enumerator. Diese Methode teilt Chunks zwischen elt_before und elt_after, wo der Block false zurückgibt.
Der Block wird mit der Länge des empfangenden Enumerators minus eins aufgerufen.
Der Ergebnis-Enumerator ergibt die gechunkten Elemente als Array. Daher kann die Methode each wie folgt aufgerufen werden
enum.chunk_while { |elt_before, elt_after| bool }.each { |ary| ... }
Andere Methoden der Enumerator-Klasse und des Enumerable-Moduls, wie z. B. to_a, map usw., sind ebenfalls verwendbar.
Zum Beispiel kann eine schrittweise zunehmende Teilsequenz wie folgt gechunked werden
a = [1,2,4,9,10,11,12,15,16,19,20,21] b = a.chunk_while {|i, j| i+1 == j } p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]] c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" } p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"] d = c.join(",") p d #=> "1,2,4,9-12,15,16,19-21"
Eine zunehmende (nicht abnehmende) Teilsequenz kann wie folgt gechunked werden
a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5] p a.chunk_while {|i, j| i <= j }.to_a #=> [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]
Benachbarte gerade und ungerade Zahlen können wie folgt gechunked werden: (Enumerable#chunk ist eine andere Möglichkeit, dies zu tun.)
a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0] p a.chunk_while {|i, j| i.even? == j.even? }.to_a #=> [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]
Enumerable#slice_when macht dasselbe, außer dass es schneidet, wenn der Block true anstelle von false zurückgibt.
Source
static VALUE
enum_collect(VALUE obj)
{
VALUE ary;
int min_argc, max_argc;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
min_argc = rb_block_min_max_arity(&max_argc);
rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
return ary;
}
Source
static VALUE
enum_compact(VALUE obj)
{
VALUE ary;
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, compact_i, ary);
return ary;
}
Gibt ein Array aller Nicht-nil-Elemente zurück
a = [nil, 0, nil, 'a', false, nil, false, nil, 'a', nil, 0, nil] a.compact # => [0, "a", false, false, "a", 0]
Source
static VALUE
enum_count(int argc, VALUE *argv, VALUE obj)
{
VALUE item = Qnil;
struct MEMO *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 = MEMO_NEW(item, 0, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return imemo_count_value(memo);
}
Gibt die Anzahl der Elemente zurück, basierend auf einem Argument oder einer Block-Bedingung, falls angegeben.
Ohne Argument und ohne Block wird die Anzahl der Elemente zurückgegeben
[0, 1, 2].count # => 3 {foo: 0, bar: 1, baz: 2}.count # => 3
Mit dem Argument object wird die Anzahl der Elemente zurückgegeben, die == object sind
[0, 1, 2, 1].count(1) # => 2
Mit einem Block wird der Block mit jedem Element aufgerufen und die Anzahl der Elemente zurückgegeben, für die der Block einen wahrheitsfähigen Wert zurückgibt
[0, 1, 2, 3].count {|element| element < 2} # => 2 {foo: 0, bar: 1, baz: 2}.count {|key, value| value < 2} # => 2
Source
static VALUE
enum_cycle(int argc, VALUE *argv, VALUE obj)
{
VALUE ary;
VALUE nv = Qnil;
long n, i, len;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size);
if (!argc || NIL_P(nv = argv[0])) {
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++) {
enum_yield_array(RARRAY_AREF(ary, i));
}
}
return Qnil;
}
Wenn es mit einem positiven Ganzzahl-Argument n und einem Block aufgerufen wird, ruft es den Block mit jedem Element auf, dann wiederholt es dies, bis es dies n Mal getan hat; gibt nil zurück
a = [] (1..4).cycle(3) {|element| a.push(element) } # => nil a # => [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4] a = [] ('a'..'d').cycle(2) {|element| a.push(element) } a # => ["a", "b", "c", "d", "a", "b", "c", "d"] a = [] {foo: 0, bar: 1, baz: 2}.cycle(2) {|element| a.push(element) } a # => [[:foo, 0], [:bar, 1], [:baz, 2], [:foo, 0], [:bar, 1], [:baz, 2]]
Wenn die Anzahl null oder negativ ist, wird der Block nicht aufgerufen.
Wenn es mit einem Block und n gleich nil aufgerufen wird, wird es für immer durchlaufen.
Wenn kein Block gegeben ist, wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_drop(VALUE obj, VALUE n)
{
VALUE result;
struct MEMO *memo;
long len = NUM2LONG(n);
if (len < 0) {
rb_raise(rb_eArgError, "attempt to drop negative size");
}
result = rb_ary_new();
memo = MEMO_NEW(result, 0, len);
rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
return result;
}
Für eine positive Ganzzahl n gibt es ein Array zurück, das alle bis auf die ersten n Elemente enthält
r = (1..4) r.drop(3) # => [4] r.drop(2) # => [3, 4] r.drop(1) # => [2, 3, 4] r.drop(0) # => [1, 2, 3, 4] r.drop(50) # => [] h = {foo: 0, bar: 1, baz: 2, bat: 3} h.drop(2) # => [[:baz, 2], [:bat, 3]]
Source
static VALUE
enum_drop_while(VALUE obj)
{
VALUE result;
struct MEMO *memo;
RETURN_ENUMERATOR(obj, 0, 0);
result = rb_ary_new();
memo = MEMO_NEW(result, 0, FALSE);
rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
return result;
}
Ruft den Block mit aufeinanderfolgenden Elementen auf, solange der Block einen wahrheitsfähigen Wert zurückgibt; gibt ein Array aller Elemente danach zurück
(1..4).drop_while{|i| i < 3 } # => [3, 4] h = {foo: 0, bar: 1, baz: 2} a = h.drop_while{|element| key, value = *element; value < 2 } a # => [[:baz, 2]]
Ohne Block wird ein Enumerator zurückgegeben.
e = (1..4).drop_while p e #=> #<Enumerator: 1..4:drop_while> i = e.next; p i; e.feed(i < 3) #=> 1 i = e.next; p i; e.feed(i < 3) #=> 2 i = e.next; p i; e.feed(i < 3) #=> 3 begin e.next rescue StopIteration p $!.result #=> [3, 4] end
Source
static VALUE
enum_each_cons(VALUE obj, VALUE n)
{
long size = NUM2LONG(n);
struct MEMO *memo;
int arity;
if (size <= 0) rb_raise(rb_eArgError, "invalid size");
RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
arity = rb_block_arity();
if (enum_size_over_p(obj, size)) return obj;
memo = MEMO_NEW(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
return obj;
}
Ruft den Block mit jedem aufeinanderfolgenden überlappenden n-Tupel von Elementen auf; gibt self zurück
a = [] (1..5).each_cons(3) {|element| a.push(element) } a # => [[1, 2, 3], [2, 3, 4], [3, 4, 5]] a = [] h = {foo: 0, bar: 1, baz: 2, bam: 3} h.each_cons(2) {|element| a.push(element) } a # => [[[:foo, 0], [:bar, 1]], [[:bar, 1], [:baz, 2]], [[:baz, 2], [:bam, 3]]]
Ohne Block wird ein Enumerator zurückgegeben.
Source
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;
}
Ruft den gegebenen Block mit jedem Element auf, wobei mehrere Werte von yield zu einem Array konvertiert werden; gibt self zurück
a = [] (1..4).each_entry {|element| a.push(element) } # => 1..4 a # => [1, 2, 3, 4] a = [] h = {foo: 0, bar: 1, baz:2} h.each_entry {|element| a.push(element) } # => {:foo=>0, :bar=>1, :baz=>2} a # => [[:foo, 0], [:bar, 1], [:baz, 2]] class Foo include Enumerable def each yield 1 yield 1, 2 yield end end Foo.new.each_entry {|yielded| p yielded }
Ausgabe
1 [1, 2] nil
Ohne Block wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_each_slice(VALUE obj, VALUE n)
{
long size = NUM2LONG(n);
VALUE ary;
struct MEMO *memo;
int arity;
if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size);
size = limit_by_enum_size(obj, size);
ary = rb_ary_new2(size);
arity = rb_block_arity();
memo = MEMO_NEW(ary, dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
ary = memo->v1;
if (RARRAY_LEN(ary) > 0) rb_yield(ary);
return obj;
}
Ruft den Block mit jedem aufeinanderfolgenden, disjunkten n-Tupel von Elementen auf; gibt self zurück
a = [] (1..10).each_slice(3) {|tuple| a.push(tuple) } a # => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]] a = [] h = {foo: 0, bar: 1, baz: 2, bat: 3, bam: 4} h.each_slice(2) {|tuple| a.push(tuple) } a # => [[[:foo, 0], [:bar, 1]], [[:baz, 2], [:bat, 3]], [[:bam, 4]]]
Ohne Block wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_each_with_index(int argc, VALUE *argv, VALUE obj)
{
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
rb_block_call(obj, id_each, argc, argv, each_with_index_i, INT2FIX(0));
return obj;
}
Ruft self.each mit *args auf. Mit einem gegebenen Block erhält der Block jedes Element und seinen Index; gibt self zurück
h = {} (1..4).each_with_index {|element, i| h[element] = i } # => 1..4 h # => {1=>0, 2=>1, 3=>2, 4=>3} h = {} %w[a b c d].each_with_index {|element, i| h[element] = i } # => ["a", "b", "c", "d"] h # => {"a"=>0, "b"=>1, "c"=>2, "d"=>3} a = [] h = {foo: 0, bar: 1, baz: 2} h.each_with_index {|element, i| a.push([i, element]) } # => {:foo=>0, :bar=>1, :baz=>2} a # => [[0, [:foo, 0]], [1, [:bar, 1]], [2, [:baz, 2]]]
Ohne Block wird ein Enumerator zurückgegeben.
Source
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;
}
Ruft den Block einmal für jedes Element auf und übergibt sowohl das Element als auch das gegebene Objekt
(1..4).each_with_object([]) {|i, a| a.push(i**2) } # => [1, 4, 9, 16] {foo: 0, bar: 1, baz: 2}.each_with_object({}) {|(k, v), h| h[v] = k } # => {0=>:foo, 1=>:bar, 2=>:baz}
Ohne Block wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_filter_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, filter_map_i, ary);
return ary;
}
Gibt ein Array von wahrheitsfähigen Elementen zurück, die vom Block zurückgegeben werden.
Mit einem gegebenen Block wird der Block mit aufeinanderfolgenden Elementen aufgerufen; gibt ein Array jedes wahrheitsfähigen Wertes zurück, der vom Block zurückgegeben wird
(0..9).filter_map {|i| i * 2 if i.even? } # => [0, 4, 8, 12, 16] {foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } # => [:foo, :baz]
Wenn kein Block gegeben ist, wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_find(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE if_none;
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
RETURN_ENUMERATOR(obj, argc, argv);
memo = MEMO_NEW(Qundef, 0, 0);
if (rb_block_pair_yield_optimizable())
rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
else
rb_block_call2(obj, id_each, 0, 0, find_i, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
if (memo->u3.cnt) {
return memo->v1;
}
if (!NIL_P(if_none)) {
return rb_funcallv(if_none, id_call, 0, 0);
}
return Qnil;
}
Gibt das erste Element zurück, für das der Block einen wahrheitsfähigen Wert zurückgibt.
Mit einem gegebenen Block wird der Block mit aufeinanderfolgenden Elementen der Sammlung aufgerufen; gibt das erste Element zurück, für das der Block einen wahrheitsfähigen Wert zurückgibt
(0..9).find {|element| element > 2} # => 3
Wenn kein solches Element gefunden wird, wird if_none_proc aufgerufen und dessen Rückgabewert zurückgegeben.
(0..9).find(proc {false}) {|element| element > 12} # => false {foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') } # => [:bar, 1] {foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
Ohne Block wird ein Enumerator zurückgegeben.
Source
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;
}
Source
static VALUE
enum_find_index(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *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 = MEMO_NEW(Qnil, condition_value, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return memo->v1;
}
Gibt den Index des ersten Elements zurück, das eine bestimmte Bedingung erfüllt, oder nil, wenn kein solches Element gefunden wird.
Mit dem Argument object wird der Index des ersten Elements zurückgegeben, das == object ist
['a', 'b', 'c', 'b'].find_index('b') # => 1
Mit einem Block wird der Block mit aufeinanderfolgenden Elementen aufgerufen; gibt das erste Element zurück, für das der Block einen wahrheitsfähigen Wert zurückgibt
['a', 'b', 'c', 'b'].find_index {|element| element.start_with?('b') } # => 1 {foo: 0, bar: 1, baz: 2}.find_index {|key, value| value > 1 } # => 2
Ohne Argument und ohne Block wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_first(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
rb_check_arity(argc, 0, 1);
if (argc > 0) {
return enum_take(obj, argv[0]);
}
else {
memo = MEMO_NEW(Qnil, 0, 0);
rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
return memo->v1;
}
}
Gibt das erste Element oder die ersten Elemente zurück.
Ohne Argument wird das erste Element zurückgegeben, oder nil, wenn keines vorhanden ist
(1..4).first # => 1 %w[a b c].first # => "a" {foo: 1, bar: 1, baz: 2}.first # => [:foo, 1] [].first # => nil
Mit einem Ganzzahl-Argument n wird ein Array zurückgegeben, das die ersten n vorhandenen Elemente enthält
(1..4).first(2) # => [1, 2] %w[a b c d].first(3) # => ["a", "b", "c"] %w[a b c d].first(50) # => ["a", "b", "c", "d"] {foo: 1, bar: 1, baz: 2}.first(2) # => [[:foo, 1], [:bar, 1]] [].first(2) # => []
Source
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;
}
Gibt ein Array von abgeflachten Objekten zurück, die vom Block zurückgegeben werden.
Mit einem gegebenen Block wird der Block mit aufeinanderfolgenden Elementen aufgerufen; gibt ein abgeflachtes Array von Objekten zurück, die vom Block zurückgegeben werden
[0, 1, 2, 3].flat_map {|element| -element } # => [0, -1, -2, -3] [0, 1, 2, 3].flat_map {|element| [element, -element] } # => [0, 0, 1, -1, 2, -2, 3, -3] [[0, 1], [2, 3]].flat_map {|e| e + [100] } # => [0, 1, 100, 2, 3, 100] {foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
Ohne Block wird ein Enumerator zurückgegeben.
Alias: collect_concat.
Source
static VALUE
enum_grep(VALUE obj, VALUE pat)
{
return enum_grep0(obj, pat, Qtrue);
}
Gibt ein Array von Objekten zurück, basierend auf Elementen von self, die dem gegebenen Muster entsprechen.
Ohne Block wird ein Array zurückgegeben, das jedes Element enthält, für das muster === element true ist
a = ['foo', 'bar', 'car', 'moo'] a.grep(/ar/) # => ["bar", "car"] (1..10).grep(3..8) # => [3, 4, 5, 6, 7, 8] ['a', 'b', 0, 1].grep(Integer) # => [0, 1]
Mit einem gegebenen Block wird der Block mit jedem übereinstimmenden Element aufgerufen und ein Array zurückgegeben, das jedes vom Block zurückgegebene Objekt enthält
a = ['foo', 'bar', 'car', 'moo'] a.grep(/ar/) {|element| element.upcase } # => ["BAR", "CAR"]
Zugehörig: grep_v.
Source
static VALUE
enum_grep_v(VALUE obj, VALUE pat)
{
return enum_grep0(obj, pat, Qfalse);
}
Gibt ein Array von Objekten zurück, basierend auf Elementen von self, die dem gegebenen Muster *nicht* entsprechen.
Ohne Block wird ein Array zurückgegeben, das jedes Element enthält, für das muster === element false ist
a = ['foo', 'bar', 'car', 'moo'] a.grep_v(/ar/) # => ["foo", "moo"] (1..10).grep_v(3..8) # => [1, 2, 9, 10] ['a', 'b', 0, 1].grep_v(Integer) # => ["a", "b"]
Mit einem gegebenen Block wird der Block mit jedem nicht übereinstimmenden Element aufgerufen und ein Array zurückgegeben, das jedes vom Block zurückgegebene Objekt enthält
a = ['foo', 'bar', 'car', 'moo'] a.grep_v(/ar/) {|element| element.upcase } # => ["FOO", "MOO"]
Zugehörig: grep.
Source
static VALUE
enum_group_by(VALUE obj)
{
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
return enum_hashify(obj, 0, 0, group_by_i);
}
Mit einem gegebenen Block wird ein Hash zurückgegeben
-
Jeder Schlüssel ist ein Rückgabewert des Blocks.
-
Jeder Wert ist ein Array der Elemente, für die der Block diesen Schlüssel zurückgegeben hat.
Beispiele
g = (1..6).group_by {|i| i%3 } g # => {1=>[1, 4], 2=>[2, 5], 0=>[3, 6]} h = {foo: 0, bar: 1, baz: 0, bat: 1} g = h.group_by {|key, value| value } g # => {0=>[[:foo, 0], [:baz, 0]], 1=>[[:bar, 1], [:bat, 1]]}
Ohne Block wird ein Enumerator zurückgegeben.
Gibt zurück, ob für irgendein Element object == element gilt
(1..4).include?(2) # => true (1..4).include?(5) # => false (1..4).include?('2') # => false %w[a b c d].include?('b') # => true %w[a b c d].include?('2') # => false {foo: 0, bar: 1, baz: 2}.include?(:foo) # => true {foo: 0, bar: 1, baz: 2}.include?('foo') # => false {foo: 0, bar: 1, baz: 2}.include?(0) # => false
Source
static VALUE
enum_inject(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE init, op;
rb_block_call_func *iter = inject_i;
ID id;
int num_args;
if (rb_block_given_p()) {
num_args = rb_scan_args(argc, argv, "02", &init, &op);
}
else {
num_args = rb_scan_args(argc, argv, "11", &init, &op);
}
switch (num_args) {
case 0:
init = Qundef;
break;
case 1:
if (rb_block_given_p()) {
break;
}
id = rb_check_id(&init);
op = id ? ID2SYM(id) : init;
init = Qundef;
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;
}
if (iter == inject_op_i &&
SYMBOL_P(op) &&
RB_TYPE_P(obj, T_ARRAY) &&
rb_method_basic_definition_p(CLASS_OF(obj), id_each)) {
return ary_inject_op(obj, init, op);
}
memo = MEMO_NEW(init, Qnil, op);
rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
if (UNDEF_P(memo->v1)) return Qnil;
return memo->v1;
}
Gibt das Ergebnis der Anwendung eines Reducers auf einen Anfangswert und das erste Element der Enumerable zurück. Dann nimmt es das Ergebnis und wendet die Funktion darauf und auf das zweite Element der Sammlung an und so weiter. Der Rückgabewert ist das Ergebnis, das vom letzten Funktionsaufruf zurückgegeben wird.
Sie können sich das vorstellen
[ a, b, c, d ].inject(i) { |r, v| fn(r, v) }
als
fn(fn(fn(fn(i, a), b), c), d)
Auf eine gewisse Weise *injiziert* die inject-Funktion die Funktion zwischen die Elemente der Enumerable.
inject ist als reduce aliasiert. Sie verwenden es, wenn Sie eine Sammlung auf einen einzelnen Wert *reduzieren* möchten.
Die Aufrufsequenzen
Beginnen wir mit der ausführlichsten
enum.inject(initial_value) do |result, next_value| # do something with +result+ and +next_value+ # the value returned by the block becomes the # value passed in to the next iteration # as +result+ end
Zum Beispiel
product = [ 2, 3, 4 ].inject(1) do |result, next_value| result * next_value end product #=> 24
Wenn dies ausgeführt wird, wird der Block zuerst mit 1 (dem Anfangswert) und 2 (dem ersten Element des Arrays) aufgerufen. Der Block gibt 1*2 zurück, so dass in der nächsten Iteration der Block mit 2 (dem vorherigen Ergebnis) und 3 aufgerufen wird. Der Block gibt 6 zurück und wird ein letztes Mal mit 6 und 4 aufgerufen. Das Ergebnis des Blocks, 24, wird zum von inject zurückgegebenen Wert. Dieser Code gibt das Produkt der Elemente in der Enumerable zurück.
Erste Abkürzung: Standard-Anfangswert
Im Fall des vorherigen Beispiels war der Anfangswert 1 nicht wirklich notwendig: Die Berechnung des Produkts einer Zahlenliste ist in sich abgeschlossen.
Unter diesen Umständen können Sie den Parameter initial_value weglassen. inject ruft dann zunächst den Block mit dem ersten Element der Sammlung als Parameter result und dem zweiten Element als next_value auf.
[ 2, 3, 4 ].inject do |result, next_value| result * next_value end
Diese Abkürzung ist praktisch, kann aber nur verwendet werden, wenn der Block ein Ergebnis liefert, das als erster Parameter zurückgegeben werden kann.
Hier ist ein Beispiel, bei dem dies nicht der Fall ist: Es gibt einen Hash zurück, bei dem die Schlüssel Wörter und die Werte die Anzahl des Vorkommens dieses Wortes in der Enumerable sind.
freqs = File.read("README.md")
.scan(/\w{2,}/)
.reduce(Hash.new(0)) do |counts, word|
counts[word] += 1
counts
end
freqs #=> {"Actions"=>4,
"Status"=>5,
"MinGW"=>3,
"https"=>27,
"github"=>10,
"com"=>15, ...
Beachten Sie, dass die letzte Zeile des Blocks nur das Wort counts ist. Dies stellt sicher, dass der Rückgabewert des Blocks das berechnete Ergebnis ist.
Zweite Abkürzung: Eine Reducer-Funktion
Eine *Reducer-Funktion* ist eine Funktion, die ein partielles Ergebnis und den nächsten Wert entgegennimmt und das nächste partielle Ergebnis zurückgibt. Der Block, der an inject übergeben wird, ist ein Reducer.
Sie können einen Reducer auch als Funktion schreiben und den Namen dieser Funktion (als Symbol) an inject übergeben. Damit dies funktioniert, muss die Funktion jedoch
-
Auf dem Typ des Ergebniswertes definiert sein
-
Einen einzelnen Parameter akzeptieren, den nächsten Wert in der Sammlung, und
-
Ein aktualisiertes Ergebnis zurückgeben, das die Funktion ebenfalls implementiert.
Hier ist ein Beispiel, das Elemente zu einem String hinzufügt. Die beiden Aufrufe rufen die Funktionen String#concat und String#+ auf dem bisherigen Ergebnis auf und übergeben ihm den nächsten Wert.
s = [ "cat", " ", "dog" ].inject("", :concat) s #=> "cat dog" s = [ "cat", " ", "dog" ].inject("The result is:", :+) s #=> "The result is: cat dog"
Hier ist ein komplexeres Beispiel, bei dem das Ergebnisobjekt einen Zustand eines anderen Typs als die Enumerable-Elemente beibehält.
class Turtle def initialize @x = @y = 0 end def move(dir) case dir when "n" then @y += 1 when "s" then @y -= 1 when "e" then @x += 1 when "w" then @x -= 1 end self end end position = "nnneesw".chars.reduce(Turtle.new, :move) position #=>> #<Turtle:0x00000001052f4698 @y=2, @x=1>
Dritte Abkürzung: Reducer ohne Anfangswert
Wenn Ihr Reducer einen Wert zurückgibt, den er als Parameter akzeptieren kann, müssen Sie keinen Anfangswert übergeben. Hier ist :* der Name der *Mal*-Funktion
product = [ 2, 3, 4 ].inject(:*) product # => 24
String-Verkettung erneut
s = [ "cat", " ", "dog" ].inject(:+) s #=> "cat dog"
Und ein Beispiel, das einen Hash in ein Array von 2-Element-Unterarrays umwandelt.
nested = {foo: 0, bar: 1}.inject([], :push) nested # => [[:foo, 0], [:bar, 1]]
Source
static VALUE
enumerable_lazy(VALUE obj)
{
VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size, rb_keyword_given_p());
/* Qfalse indicates that the Enumerator::Lazy has no method name */
rb_ivar_set(result, id_method, Qfalse);
return result;
}
Gibt einen Enumerator::Lazy zurück, der die meisten Enumerable-Methoden neu definiert, um die Enumeration zu verzögern und Werte nur bei Bedarf zu enumerieren.
Beispiel
Das folgende Programm findet pythagoreische Tripel
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
Gibt ein Array von Objekten zurück, die vom Block zurückgegeben werden.
Mit einem gegebenen Block wird der Block mit aufeinanderfolgenden Elementen aufgerufen; gibt ein Array der vom Block zurückgegebenen Objekte zurück
(0..4).map {|i| i*i } # => [0, 1, 4, 9, 16] {foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
Ohne Block wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_max(int argc, VALUE *argv, VALUE obj)
{
VALUE memo;
struct max_t *m = NEW_MEMO_FOR(struct max_t, memo);
VALUE result;
VALUE num;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 0, 1, 0);
m->max = Qundef;
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 = m->max;
if (UNDEF_P(result)) return Qnil;
return result;
}
Gibt das Element mit dem maximalen Element gemäß einer gegebenen Bedingung zurück. Die Reihenfolge gleicher Elemente ist unbestimmt und kann instabil sein.
Ohne Argument und ohne Block wird das maximale Element zurückgegeben, wobei die eigene Methode <=> der Elemente zum Vergleich verwendet wird
(1..4).max # => 4 (-4..-1).max # => -1 %w[d c b a].max # => "d" {foo: 0, bar: 1, baz: 2}.max # => [:foo, 0] [].max # => nil
Mit einem positiven Ganzzahl-Argument n und ohne Block wird ein Array zurückgegeben, das die ersten n maximalen vorhandenen Elemente enthält
(1..4).max(2) # => [4, 3] (-4..-1).max(2) # => [-1, -2] %w[d c b a].max(2) # => ["d", "c"] {foo: 0, bar: 1, baz: 2}.max(2) # => [[:foo, 0], [:baz, 2]] [].max(2) # => []
Mit einem gegebenen Block bestimmt der Block die maximalen Elemente. Der Block wird mit zwei Elementen a und b aufgerufen und muss zurückgeben
-
Eine negative Ganzzahl, wenn
a < b. -
Null, wenn
a == b. -
Eine positive Ganzzahl, wenn
a > b.
Mit einem gegebenen Block und ohne Argument wird das maximale Element zurückgegeben, wie es der Block bestimmt
%w[xxx x xxxx xx].max {|a, b| a.size <=> b.size } # => "xxxx" h = {foo: 0, bar: 1, baz: 2} h.max {|pair1, pair2| pair1[1] <=> pair2[1] } # => [:baz, 2] [].max {|a, b| a <=> b } # => nil
Mit einem gegebenen Block und einem positiven Ganzzahl-Argument n wird ein Array zurückgegeben, das die ersten n maximalen vorhandenen Elemente enthält, wie sie vom Block bestimmt werden.
%w[xxx x xxxx xx].max(2) {|a, b| a.size <=> b.size } # => ["xxxx", "xxx"] h = {foo: 0, bar: 1, baz: 2} h.max(2) {|pair1, pair2| pair1[1] <=> pair2[1] } # => [[:baz, 2], [:bar, 1]] [].max(2) {|a, b| a <=> b } # => []
Source
static VALUE
enum_max_by(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE num;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 1, 0);
memo = MEMO_NEW(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
return memo->v2;
}
Gibt die Elemente zurück, für die der Block die maximalen Werte zurückgibt.
Mit einem gegebenen Block und ohne Argument wird das Element zurückgegeben, für das der Block den maximalen Wert zurückgibt
(1..4).max_by {|element| -element } # => 1 %w[a b c d].max_by {|element| -element.ord } # => "a" {foo: 0, bar: 1, baz: 2}.max_by {|key, value| -value } # => [:foo, 0] [].max_by {|element| -element } # => nil
Mit einem gegebenen Block und einem positiven Ganzzahl-Argument n wird ein Array zurückgegeben, das die n Elemente enthält, für die der Block maximale Werte zurückgibt
(1..4).max_by(2) {|element| -element } # => [1, 2] %w[a b c d].max_by(2) {|element| -element.ord } # => ["a", "b"] {foo: 0, bar: 1, baz: 2}.max_by(2) {|key, value| -value } # => [[:foo, 0], [:bar, 1]] [].max_by(2) {|element| -element } # => []
Gibt einen Enumerator zurück, wenn kein Block gegeben ist.
Source
static VALUE
enum_member(VALUE obj, VALUE val)
{
struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);
rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
return memo->v2;
}
Source
static VALUE
enum_min(int argc, VALUE *argv, VALUE obj)
{
VALUE memo;
struct min_t *m = NEW_MEMO_FOR(struct min_t, memo);
VALUE result;
VALUE num;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 0, 0, 0);
m->min = Qundef;
if (rb_block_given_p()) {
rb_block_call(obj, id_each, 0, 0, min_ii, memo);
}
else {
rb_block_call(obj, id_each, 0, 0, min_i, memo);
}
result = m->min;
if (UNDEF_P(result)) return Qnil;
return result;
}
Gibt das Element mit dem minimalen Element gemäß einer gegebenen Bedingung zurück. Die Reihenfolge gleicher Elemente ist unbestimmt und kann instabil sein.
Ohne Argument und ohne Block wird das minimale Element zurückgegeben, wobei die eigene Methode <=> der Elemente zum Vergleich verwendet wird
(1..4).min # => 1 (-4..-1).min # => -4 %w[d c b a].min # => "a" {foo: 0, bar: 1, baz: 2}.min # => [:bar, 1] [].min # => nil
Mit einem positiven Ganzzahl-Argument n und ohne Block wird ein Array zurückgegeben, das die ersten n minimalen vorhandenen Elemente enthält
(1..4).min(2) # => [1, 2] (-4..-1).min(2) # => [-4, -3] %w[d c b a].min(2) # => ["a", "b"] {foo: 0, bar: 1, baz: 2}.min(2) # => [[:bar, 1], [:baz, 2]] [].min(2) # => []
Mit einem gegebenen Block bestimmt der Block die minimalen Elemente. Der Block wird mit zwei Elementen a und b aufgerufen und muss zurückgeben
-
Eine negative Ganzzahl, wenn
a < b. -
Null, wenn
a == b. -
Eine positive Ganzzahl, wenn
a > b.
Mit einem gegebenen Block und ohne Argument wird das minimale Element zurückgegeben, wie es der Block bestimmt
%w[xxx x xxxx xx].min {|a, b| a.size <=> b.size } # => "x" h = {foo: 0, bar: 1, baz: 2} h.min {|pair1, pair2| pair1[1] <=> pair2[1] } # => [:foo, 0] [].min {|a, b| a <=> b } # => nil
Mit einem gegebenen Block und einem positiven Ganzzahl-Argument n wird ein Array zurückgegeben, das die ersten n minimalen vorhandenen Elemente enthält, wie sie vom Block bestimmt werden.
%w[xxx x xxxx xx].min(2) {|a, b| a.size <=> b.size } # => ["x", "xx"] h = {foo: 0, bar: 1, baz: 2} h.min(2) {|pair1, pair2| pair1[1] <=> pair2[1] } # => [[:foo, 0], [:bar, 1]] [].min(2) {|a, b| a <=> b } # => []
Source
static VALUE
enum_min_by(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE num;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 0, 0);
memo = MEMO_NEW(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
return memo->v2;
}
Gibt die Elemente zurück, für die der Block die minimalen Werte zurückgibt.
Mit einem gegebenen Block und ohne Argument wird das Element zurückgegeben, für das der Block den minimalen Wert zurückgibt
(1..4).min_by {|element| -element } # => 4 %w[a b c d].min_by {|element| -element.ord } # => "d" {foo: 0, bar: 1, baz: 2}.min_by {|key, value| -value } # => [:baz, 2] [].min_by {|element| -element } # => nil
Mit einem gegebenen Block und einem positiven Ganzzahl-Argument n wird ein Array zurückgegeben, das die n Elemente enthält, für die der Block minimale Werte zurückgibt
(1..4).min_by(2) {|element| -element } # => [4, 3] %w[a b c d].min_by(2) {|element| -element.ord } # => ["d", "c"] {foo: 0, bar: 1, baz: 2}.min_by(2) {|key, value| -value } # => [[:baz, 2], [:bar, 1]] [].min_by(2) {|element| -element } # => []
Gibt einen Enumerator zurück, wenn kein Block gegeben ist.
Source
static VALUE
enum_minmax(VALUE obj)
{
VALUE memo;
struct minmax_t *m = NEW_MEMO_FOR(struct minmax_t, memo);
m->min = Qundef;
m->last = Qundef;
if (rb_block_given_p()) {
rb_block_call(obj, id_each, 0, 0, minmax_ii, memo);
if (!UNDEF_P(m->last))
minmax_ii_update(m->last, m->last, m);
}
else {
rb_block_call(obj, id_each, 0, 0, minmax_i, memo);
if (!UNDEF_P(m->last))
minmax_i_update(m->last, m->last, m);
}
if (!UNDEF_P(m->min)) {
return rb_assoc_new(m->min, m->max);
}
return rb_assoc_new(Qnil, Qnil);
}
Gibt ein 2-elementiges Array zurück, das das minimale und maximale Element gemäß einer gegebenen Bedingung enthält. Die Reihenfolge gleicher Elemente ist unbestimmt und kann instabil sein.
Gibt ohne Argument und ohne Block die kleinsten und größten Elemente zurück, wobei die eigene Methode <=> der Elemente zum Vergleich verwendet wird.
(1..4).minmax # => [1, 4] (-4..-1).minmax # => [-4, -1] %w[d c b a].minmax # => ["a", "d"] {foo: 0, bar: 1, baz: 2}.minmax # => [[:bar, 1], [:foo, 0]] [].minmax # => [nil, nil]
Mit einem gegebenen Block gibt die kleinsten und größten Elemente zurück, wie vom Block bestimmt.
%w[xxx x xxxx xx].minmax {|a, b| a.size <=> b.size } # => ["x", "xxxx"] h = {foo: 0, bar: 1, baz: 2} h.minmax {|pair1, pair2| pair1[1] <=> pair2[1] } # => [[:foo, 0], [:baz, 2]] [].minmax {|a, b| a <=> b } # => [nil, nil]
Source
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 (!UNDEF_P(m->last_bv))
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);
}
Gibt ein 2-elementiges Array zurück, das die Elemente enthält, für die der Block minimale und maximale Werte zurückgibt.
(1..4).minmax_by {|element| -element } # => [4, 1] %w[a b c d].minmax_by {|element| -element.ord } # => ["d", "a"] {foo: 0, bar: 1, baz: 2}.minmax_by {|key, value| -value } # => [[:baz, 2], [:foo, 0]] [].minmax_by {|element| -element } # => [nil, nil]
Gibt einen Enumerator zurück, wenn kein Block gegeben ist.
Source
static VALUE
enum_none(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(none);
return memo->v1;
}
Gibt zurück, ob kein Element eine gegebene Bedingung erfüllt.
Ohne Argument und ohne Block wird zurückgegeben, ob kein Element wahrheitsgemäß ist.
(1..4).none? # => false [nil, false].none? # => true {foo: 0}.none? # => false {foo: 0, bar: 1}.none? # => false [].none? # => true
Mit dem Argument pattern und ohne Block wird zurückgegeben, ob für kein Element element gilt: pattern === element.
[nil, false, 1.1].none?(Integer) # => true %w[bar baz bat bam].none?(/m/) # => false %w[bar baz bat bam].none?(/foo/) # => true %w[bar baz bat bam].none?('ba') # => true {foo: 0, bar: 1, baz: 2}.none?(Hash) # => true {foo: 0}.none?(Array) # => false [].none?(Integer) # => true
Mit einem gegebenen Block wird zurückgegeben, ob der Block für kein Element einen wahrheitsgemäßen Wert zurückgibt.
(1..4).none? {|element| element < 1 } # => true (1..4).none? {|element| element < 2 } # => false {foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 0 } # => true {foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 1 } # => false
Source
static VALUE
enum_one(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qundef);
VALUE result;
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(one);
result = memo->v1;
if (UNDEF_P(result)) return Qfalse;
return result;
}
Gibt zurück, ob genau ein Element eine gegebene Bedingung erfüllt.
Ohne Argument und ohne Block wird zurückgegeben, ob genau ein Element wahrheitsgemäß ist.
(1..1).one? # => true [1, nil, false].one? # => true (1..4).one? # => false {foo: 0}.one? # => true {foo: 0, bar: 1}.one? # => false [].one? # => false
Mit dem Argument pattern und ohne Block wird zurückgegeben, ob für genau ein Element element gilt: pattern === element.
[nil, false, 0].one?(Integer) # => true [nil, false, 0].one?(Numeric) # => true [nil, false, 0].one?(Float) # => false %w[bar baz bat bam].one?(/m/) # => true %w[bar baz bat bam].one?(/foo/) # => false %w[bar baz bat bam].one?('ba') # => false {foo: 0, bar: 1, baz: 2}.one?(Array) # => false {foo: 0}.one?(Array) # => true [].one?(Integer) # => false
Mit einem gegebenen Block wird zurückgegeben, ob der Block für genau ein Element einen wahrheitsgemäßen Wert zurückgibt.
(1..4).one? {|element| element < 2 } # => true (1..4).one? {|element| element < 1 } # => false {foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 1 } # => true {foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 2 } # => false
Source
static VALUE
enum_partition(VALUE obj)
{
struct MEMO *memo;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
memo = MEMO_NEW(rb_ary_new(), rb_ary_new(), 0);
rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
return rb_assoc_new(memo->v1, memo->v2);
}
Mit einem gegebenen Block wird ein Array aus zwei Arrays zurückgegeben.
-
Das erste Array enthält die Elemente, für die der Block einen wahrheitsgemäßen Wert zurückgibt.
-
Das andere Array enthält alle anderen Elemente.
Beispiele
p = (1..4).partition {|i| i.even? } p # => [[2, 4], [1, 3]] p = ('a'..'d').partition {|c| c < 'c' } p # => [["a", "b"], ["c", "d"]] h = {foo: 0, bar: 1, baz: 2, bat: 3} p = h.partition {|key, value| key.start_with?('b') } p # => [[[:bar, 1], [:baz, 2], [:bat, 3]], [[:foo, 0]]] p = h.partition {|key, value| value < 2 } p # => [[[:foo, 0], [:bar, 1]], [[:baz, 2], [:bat, 3]]]
Ohne Block wird ein Enumerator zurückgegeben.
Verwandt: Enumerable#group_by.
Source
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;
}
Gibt ein Array von Objekten zurück, die vom Block abgelehnt wurden.
Mit einem gegebenen Block wird der Block mit aufeinanderfolgenden Elementen aufgerufen; es wird ein Array der Elemente zurückgegeben, für die der Block nil oder false zurückgibt.
(0..9).reject {|i| i * 2 if i.even? } # => [1, 3, 5, 7, 9] {foo: 0, bar: 1, baz: 2}.reject {|key, value| key if value.odd? } # => {:foo=>0, :baz=>2}
Wenn kein Block gegeben ist, wird ein Enumerator zurückgegeben.
Verwandt: select.
Source
static VALUE
enum_reverse_each(int argc, VALUE *argv, VALUE obj)
{
VALUE ary;
long len;
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
ary = enum_to_a(argc, argv, obj);
len = RARRAY_LEN(ary);
while (len--) {
long nlen;
rb_yield(RARRAY_AREF(ary, len));
nlen = RARRAY_LEN(ary);
if (nlen < len) {
len = nlen;
}
}
return obj;
}
Mit einem gegebenen Block wird der Block mit jedem Element aufgerufen, jedoch in umgekehrter Reihenfolge; es wird self zurückgegeben.
a = [] (1..4).reverse_each {|element| a.push(-element) } # => 1..4 a # => [-4, -3, -2, -1] a = [] %w[a b c d].reverse_each {|element| a.push(element) } # => ["a", "b", "c", "d"] a # => ["d", "c", "b", "a"] a = [] h.reverse_each {|element| a.push(element) } # => {:foo=>0, :bar=>1, :baz=>2} a # => [[:baz, 2], [:bar, 1], [:foo, 0]]
Ohne Block wird ein Enumerator zurückgegeben.
Gibt ein Array zurück, das die vom Block ausgewählten Elemente enthält.
Mit einem gegebenen Block wird der Block mit aufeinanderfolgenden Elementen aufgerufen; es wird ein Array der Elemente zurückgegeben, für die der Block einen wahrheitsgemäßen Wert zurückgibt.
(0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9] a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') } a # => {:bar=>1, :baz=>2}
Ohne Block wird ein Enumerator zurückgegeben.
Verwandt: reject.
Source
static VALUE
enum_slice_after(int argc, VALUE *argv, VALUE enumerable)
{
VALUE enumerator;
VALUE pat = Qnil, pred = Qnil;
if (rb_block_given_p()) {
if (0 < argc)
rb_raise(rb_eArgError, "both pattern and block are given");
pred = rb_block_proc();
}
else {
rb_scan_args(argc, argv, "1", &pat);
}
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_sliceafter_enum, enumerable);
rb_ivar_set(enumerator, id_sliceafter_pat, pat);
rb_ivar_set(enumerator, id_sliceafter_pred, pred);
rb_block_call(enumerator, idInitialize, 0, 0, sliceafter_i, enumerator);
return enumerator;
}
Erstellt einen Enumerator für die gechunkuhten Elemente. Die Enden der Chunks werden durch pattern und den Block definiert.
Wenn pattern === elt true zurückgibt oder der Block für das Element true zurückgibt, ist das Element das Ende eines Chunks.
Die === und Block werden vom ersten bis zum letzten Element von enum aufgerufen.
Der Ergebnis-Enumerator ergibt die gechunkten Elemente als Array. Daher kann die Methode each wie folgt aufgerufen werden
enum.slice_after(pattern).each { |ary| ... }
enum.slice_after { |elt| bool }.each { |ary| ... }
Andere Methoden der Klasse Enumerator und des Moduls Enumerable, wie z. B. map usw., sind ebenfalls verwendbar.
Beispielsweise können Fortsetzungszeilen (Zeilen, die mit einem Backslash enden) wie folgt verkettet werden
lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"] e = lines.slice_after(/(?<!\\)\n\z/) p e.to_a #=> [["foo\n"], ["bar\\\n", "baz\n"], ["\n"], ["qux\n"]] p e.map {|ll| ll[0...-1].map {|l| l.sub(/\\\n\z/, "") }.join + ll.last } #=>["foo\n", "barbaz\n", "\n", "qux\n"]
Source
static VALUE
enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
{
VALUE enumerator;
if (rb_block_given_p()) {
if (argc != 0)
rb_error_arity(argc, 0, 0);
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicebefore_sep_pred, rb_block_proc());
}
else {
VALUE sep_pat;
rb_scan_args(argc, argv, "1", &sep_pat);
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicebefore_sep_pat, sep_pat);
}
rb_ivar_set(enumerator, id_slicebefore_enumerable, enumerable);
rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator);
return enumerator;
}
Mit dem Argument pattern wird ein Enumerator zurückgegeben, der das Muster verwendet, um Elemente in Arrays ("Slices") zu partitionieren. Ein Element beginnt einen neuen Slice, wenn element === pattern (oder wenn es das erste Element ist).
a = %w[foo bar fop for baz fob fog bam foy] e = a.slice_before(/ba/) # => #<Enumerator: ...> e.each {|array| p array }
Ausgabe
["foo"] ["bar", "fop", "for"] ["baz", "fob", "fog"] ["bam", "foy"]
Mit einem Block wird ein Enumerator zurückgegeben, der den Block verwendet, um Elemente in Arrays zu partitionieren. Ein Element beginnt einen neuen Slice, wenn sein Block-Rückgabewert wahrheitsgemäß ist (oder wenn es das erste Element ist).
e = (1..20).slice_before {|i| i % 4 == 2 } # => #<Enumerator: ...> e.each {|array| p array }
Ausgabe
[1] [2, 3, 4, 5] [6, 7, 8, 9] [10, 11, 12, 13] [14, 15, 16, 17] [18, 19, 20]
Andere Methoden der Enumerator-Klasse und des Enumerable-Moduls, wie z. B. to_a, map usw., sind ebenfalls verwendbar.
Beispielsweise kann die Iteration über ChangeLog-Einträge wie folgt implementiert werden
# 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“ erzeugt mehrzeilige Ausgaben für jede Datei. Diese können wie folgt gechunked werden
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"] # ...
Wenn der Block über mehrere Elemente hinweg Zustände beibehalten muss, können lokale Variablen verwendet werden. Beispielsweise können drei oder mehr aufeinanderfolgende steigende Zahlen wie folgt zusammengefasst werden (siehe chunk_while für eine bessere Methode)
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"
Lokale Variablen sollten jedoch vorsichtig verwendet werden, wenn der Ergebnis-Enumerator zweimal oder öfter enumeriert wird. Die lokalen Variablen sollten für jede Enumeration initialisiert werden. Enumerator.new kann hierfür verwendet werden.
# Word wrapping. This assumes all characters have same width. def wordwrap(words, maxwidth) Enumerator.new {|y| # cols is initialized in Enumerator.new. cols = 0 words.slice_before { |w| cols += 1 if cols != 0 cols += w.length if maxwidth < cols cols = w.length true else false end }.each {|ws| y.yield ws } } end text = (1..20).to_a.join(" ") enum = wordwrap(text.split(/\s+/), 10) puts "-"*10 enum.each { |ws| puts ws.join(" ") } # first enumeration. puts "-"*10 enum.each { |ws| puts ws.join(" ") } # second enumeration generates same result as the first. puts "-"*10 #=> ---------- # 1 2 3 4 5 # 6 7 8 9 10 # 11 12 13 # 14 15 16 # 17 18 19 # 20 # ---------- # 1 2 3 4 5 # 6 7 8 9 10 # 11 12 13 # 14 15 16 # 17 18 19 # 20 # ----------
mbox enthält eine Reihe von E-Mails, die mit einer Unix From-Zeile beginnen. Daher kann jede E-Mail extrahiert werden, indem vor der Unix From-Zeile gesliced wird.
# 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| emp = true f.slice_before { |line| prevemp = emp emp = line == "\n" prevemp && line.start_with?("From ") }.each { |mail| mail.pop if mail.last == "\n" pp mail } }
Source
static VALUE
enum_slice_when(VALUE enumerable)
{
VALUE enumerator;
VALUE pred;
pred = rb_block_proc();
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicewhen_enum, enumerable);
rb_ivar_set(enumerator, id_slicewhen_pred, pred);
rb_ivar_set(enumerator, id_slicewhen_inverted, Qfalse);
rb_block_call(enumerator, idInitialize, 0, 0, slicewhen_i, enumerator);
return enumerator;
}
Erstellt einen Enumerator für jedes gechunkte Element. Die Anfänge von Chunks werden durch den Block definiert.
Diese Methode teilt jeden Chunk mithilfe von benachbarten Elementen, elt_before und elt_after, im Empfänger-Enumerator. Diese Methode teilt Chunks zwischen elt_before und elt_after, wo der Block true zurückgibt.
Der Block wird mit der Länge des empfangenden Enumerators minus eins aufgerufen.
Der Ergebnis-Enumerator ergibt die gechunkten Elemente als Array. Daher kann die Methode each wie folgt aufgerufen werden
enum.slice_when { |elt_before, elt_after| bool }.each { |ary| ... }
Andere Methoden der Enumerator-Klasse und des Enumerable-Moduls, wie z. B. to_a, map usw., sind ebenfalls verwendbar.
Zum Beispiel kann eine schrittweise zunehmende Teilsequenz wie folgt gechunked werden
a = [1,2,4,9,10,11,12,15,16,19,20,21] b = a.slice_when {|i, j| i+1 != j } p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]] c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" } p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"] d = c.join(",") p d #=> "1,2,4,9-12,15,16,19-21"
Nahe gelegene Elemente (Schwellenwert: 6) in einem sortierten Array können wie folgt gechunked werden
a = [3, 11, 14, 25, 28, 29, 29, 41, 55, 57] p a.slice_when {|i, j| 6 < j - i }.to_a #=> [[3], [11, 14], [25, 28, 29, 29], [41], [55, 57]]
Eine zunehmende (nicht abnehmende) Teilsequenz kann wie folgt gechunked werden
a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5] p a.slice_when {|i, j| i > j }.to_a #=> [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]
Benachbarte gerade und ungerade Zahlen können wie folgt gechunked werden: (Enumerable#chunk ist eine andere Möglichkeit, dies zu tun.)
a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0] p a.slice_when {|i, j| i.even? != j.even? }.to_a #=> [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]
Absätze (nicht-leere Zeilen mit nachfolgenden leeren Zeilen) können wie folgt gechunked werden: (Siehe Enumerable#chunk zum Ignorieren leerer Zeilen.)
lines = ["foo\n", "bar\n", "\n", "baz\n", "qux\n"] p lines.slice_when {|l1, l2| /\A\s*\z/ =~ l1 && /\S/ =~ l2 }.to_a #=> [["foo\n", "bar\n", "\n"], ["baz\n", "qux\n"]]
Enumerable#chunk_while tut dasselbe, außer dass es beim Zurückgeben von false anstelle von true durch den Block teilt.
Source
static VALUE
enum_sort(VALUE obj)
{
return rb_ary_sort_bang(enum_to_a(0, 0, obj));
}
Gibt ein Array zurück, das die sortierten Elemente von self enthält. Die Reihenfolge gleicher Elemente ist unbestimmt und kann instabil sein.
Ohne gegebenen Block vergleicht die Sortierung die Elemente mithilfe der eigenen Methode <=>
%w[b c a d].sort # => ["a", "b", "c", "d"] {foo: 0, bar: 1, baz: 2}.sort # => [[:bar, 1], [:baz, 2], [:foo, 0]]
Mit einem gegebenen Block bestimmen Vergleiche im Block die Reihenfolge. Der Block wird mit zwei Elementen a und b aufgerufen und muss Folgendes zurückgeben
-
Eine negative Ganzzahl, wenn
a < b. -
Null, wenn
a == b. -
Eine positive Ganzzahl, wenn
a > b.
Beispiele
a = %w[b c a d] a.sort {|a, b| b <=> a } # => ["d", "c", "b", "a"] h = {foo: 0, bar: 1, baz: 2} h.sort {|a, b| b <=> a } # => [[:foo, 0], [:baz, 2], [:bar, 1]]
Siehe auch sort_by. Diese implementiert einen Schwartzian Transform, der nützlich ist, wenn die Schlüsselberechnung oder der Vergleich aufwendig ist.
Source
static VALUE
enum_sort_by(VALUE obj)
{
VALUE ary, buf;
struct MEMO *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_hidden_new(SORT_BY_BUFSIZE*2);
rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
memo = MEMO_NEW(0, 0, 0);
data = (struct sort_by_data *)&memo->v1;
RB_OBJ_WRITE(memo, &data->ary, ary);
RB_OBJ_WRITE(memo, &data->buf, buf);
data->n = 0;
data->primitive_uniformed = SORT_BY_UNIFORMED((CMP_OPTIMIZABLE(FLOAT) && CMP_OPTIMIZABLE(INTEGER)),
CMP_OPTIMIZABLE(FLOAT),
CMP_OPTIMIZABLE(INTEGER));
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) {
if (data->primitive_uniformed) {
RARRAY_PTR_USE(ary, ptr,
rb_uniform_intro_sort_2((struct rb_uniform_sort_data*)ptr,
(struct rb_uniform_sort_data*)(ptr + RARRAY_LEN(ary))));
}
else {
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);
return ary;
}
Mit einem gegebenen Block wird ein Array von Elementen von self zurückgegeben, sortiert nach dem Wert, den der Block für jedes Element zurückgibt. Die Reihenfolge gleicher Elemente ist unbestimmt und kann instabil sein.
Beispiele
a = %w[xx xxx x xxxx] a.sort_by {|s| s.size } # => ["x", "xx", "xxx", "xxxx"] a.sort_by {|s| -s.size } # => ["xxxx", "xxx", "xx", "x"] h = {foo: 2, bar: 1, baz: 0} h.sort_by{|key, value| value } # => [[:baz, 0], [:bar, 1], [:foo, 2]] h.sort_by{|key, value| key } # => [[:bar, 1], [:baz, 0], [:foo, 2]]
Ohne Block wird ein Enumerator zurückgegeben.
Die aktuelle Implementierung von sort_by generiert ein Array von Tupeln, das das ursprüngliche Sammlungs-Element und den abgebildeten Wert enthält. Dies macht sort_by ziemlich aufwendig, wenn die Schlüsselsätze einfach sind.
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
ergibt
user system total real Sort 0.180000 0.000000 0.180000 ( 0.175469) Sort by 1.980000 0.040000 2.020000 ( 2.013586)
Betrachten Sie jedoch den Fall, dass der Vergleich der Schlüssel eine nicht-triviale Operation ist. Der folgende Code sortiert einige Dateien nach Änderungsdatum mithilfe der grundlegenden Methode sort.
files = Dir["*"] sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime } sorted #=> ["mon", "tues", "wed", "thurs"]
Diese Sortierung ist ineffizient: Sie generiert bei jedem Vergleich zwei neue File-Objekte. Eine etwas bessere Technik ist die Verwendung der Methode Kernel#test, um die Änderungsdaten direkt zu generieren.
files = Dir["*"] sorted = files.sort { |a, b| test(?M, a) <=> test(?M, b) } sorted #=> ["mon", "tues", "wed", "thurs"]
Dies generiert immer noch viele unnötige Time-Objekte. Eine effizientere Technik ist das Caching der Sortierschlüssel (in diesem Fall die Änderungsdaten) vor der Sortierung. Perl-Benutzer nennen diesen Ansatz oft Schwartzian Transform, nach Randal Schwartz. Wir konstruieren ein temporäres Array, bei dem jedes Element ein Array ist, das unseren Sortierschlüssel zusammen mit dem Dateinamen enthält. Wir sortieren dieses Array und extrahieren dann den Dateinamen aus dem Ergebnis.
sorted = Dir["*"].collect { |f| [test(?M, f), f] }.sort.collect { |f| f[1] } sorted #=> ["mon", "tues", "wed", "thurs"]
Dies ist genau das, was sort_by intern tut.
sorted = Dir["*"].sort_by { |f| test(?M, f) } sorted #=> ["mon", "tues", "wed", "thurs"]
Um die Umkehrung einer bestimmten Reihenfolge zu erzeugen, kann Folgendes verwendet werden
ary.sort_by { ... }.reverse!
Source
static VALUE
enum_sum(int argc, VALUE* argv, VALUE obj)
{
struct enum_sum_memo memo;
VALUE beg, end;
int excl;
memo.v = (rb_check_arity(argc, 0, 1) == 0) ? LONG2FIX(0) : argv[0];
memo.block_given = rb_block_given_p();
memo.n = 0;
memo.r = Qundef;
if ((memo.float_value = RB_FLOAT_TYPE_P(memo.v))) {
memo.f = RFLOAT_VALUE(memo.v);
memo.c = 0.0;
}
else {
memo.f = 0.0;
memo.c = 0.0;
}
if (RTEST(rb_range_values(obj, &beg, &end, &excl))) {
if (!memo.block_given && !memo.float_value &&
(FIXNUM_P(beg) || RB_BIGNUM_TYPE_P(beg)) &&
(FIXNUM_P(end) || RB_BIGNUM_TYPE_P(end))) {
return int_range_sum(beg, end, excl, memo.v);
}
}
if (RB_TYPE_P(obj, T_HASH) &&
rb_method_basic_definition_p(CLASS_OF(obj), id_each))
hash_sum(obj, &memo);
else
rb_block_call(obj, id_each, 0, 0, enum_sum_i, (VALUE)&memo);
if (memo.float_value) {
return DBL2NUM(memo.f + memo.c);
}
else {
if (memo.n != 0)
memo.v = rb_fix_plus(LONG2FIX(memo.n), memo.v);
if (!UNDEF_P(memo.r)) {
memo.v = rb_rational_plus(memo.r, memo.v);
}
return memo.v;
}
}
Ohne gegebenen Block wird die Summe von initial_value und den Elementen zurückgegeben.
(1..100).sum # => 5050 (1..100).sum(1) # => 5051 ('a'..'d').sum('foo') # => "fooabcd"
Im Allgemeinen wird die Summe mithilfe der Methoden + und each berechnet; zur Leistungsoptimierung werden diese Methoden möglicherweise nicht verwendet, und daher hat eine Neudefinition dieser Methoden hier möglicherweise keine Wirkung.
Eine solche Optimierung: Wenn möglich, wird mit der Gaußschen Summenformel n(n+1)/2 berechnet.
100 * (100 + 1) / 2 # => 5050
Mit einem gegebenen Block wird der Block mit jedem Element aufgerufen; die Summe von initial_value und den Rückgabewerten des Blocks wird zurückgegeben.
(1..4).sum {|i| i*i } # => 30 (1..4).sum(100) {|i| i*i } # => 130 h = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5} h.sum {|key, value| value.odd? ? value : 0 } # => 9 ('a'..'f').sum('x') {|c| c < 'd' ? c : '' } # => "xabc"
Source
static VALUE
enum_take(VALUE obj, VALUE n)
{
struct MEMO *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 = MEMO_NEW(result, 0, len);
rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
return result;
}
Für eine nicht-negative ganze Zahl n werden die ersten n Elemente zurückgegeben.
r = (1..4) r.take(2) # => [1, 2] r.take(0) # => [] h = {foo: 0, bar: 1, baz: 2, bat: 3} h.take(2) # => [[:foo, 0], [:bar, 1]]
Source
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;
}
Ruft den Block mit aufeinanderfolgenden Elementen auf, solange der Block einen wahrheitsgemäßen Wert zurückgibt; es wird ein Array aller Elemente bis zu diesem Zeitpunkt zurückgegeben.
(1..4).take_while{|i| i < 3 } # => [1, 2] h = {foo: 0, bar: 1, baz: 2} h.take_while{|element| key, value = *element; value < 2 } # => [[:foo, 0], [:bar, 1]]
Ohne Block wird ein Enumerator zurückgegeben.
Source
static VALUE
enum_tally(int argc, VALUE *argv, VALUE obj)
{
VALUE hash;
if (rb_check_arity(argc, 0, 1)) {
hash = rb_to_hash_type(argv[0]);
rb_check_frozen(hash);
}
else {
hash = rb_hash_new();
}
return enum_hashify_into(obj, 0, 0, tally_i, hash);
}
Wenn das Argument hash nicht gegeben ist, wird ein neues Hash zurückgegeben, dessen Schlüssel die eindeutigen Elemente in self sind; jeder ganzzahlige Wert ist die Anzahl der Vorkommen jedes Elements.
%w[a b c b c a c b].tally # => {"a"=>2, "b"=>3, "c"=>3}
Wenn das Argument hash gegeben ist, wird hash zurückgegeben, möglicherweise erweitert; für jedes Element ele in self
-
Es wird als Schlüssel mit einem Nullwert hinzugefügt, wenn dieser Schlüssel noch nicht existiert.
hash[ele] = 0 unless hash.include?(ele)
-
Der Wert des Schlüssels
elewird inkrementiert.hash[ele] += 1
Dies ist nützlich, um Zählungen über mehrere Enumerable-Objekte hinweg zu akkumulieren.
h = {} # => {} %w[a c d b c a].tally(h) # => {"a"=>2, "c"=>2, "d"=>1, "b"=>1} %w[b a z].tally(h) # => {"a"=>3, "c"=>2, "d"=>1, "b"=>2, "z"=>1} %w[b a m].tally(h) # => {"a"=>4, "c"=>2, "d"=>1, "b"=>3, "z"=>1, "m"=>1}
Der hinzuzufügende oder zu findende Schlüssel für ein Element hängt von der Klasse von self ab; siehe Enumerable in Ruby Classes.
Beispiele
-
Array(und bestimmte Array-ähnliche Klassen): Der Schlüssel ist das Element (wie oben). -
Hash(und bestimmte Hash-ähnliche Klassen): Der Schlüssel ist das 2-elementige Array, das aus dem Schlüssel-Wert-Paar gebildet wird.h = {} # => {} {foo: 'a', bar: 'b'}.tally(h) # => {[:foo, "a"]=>1, [:bar, "b"]=>1} {foo: 'c', bar: 'd'}.tally(h) # => {[:foo, "a"]=>1, [:bar, "b"]=>1, [:foo, "c"]=>1, [:bar, "d"]=>1} {foo: 'a', bar: 'b'}.tally(h) # => {[:foo, "a"]=>2, [:bar, "b"]=>2, [:foo, "c"]=>1, [:bar, "d"]=>1} {foo: 'c', bar: 'd'}.tally(h) # => {[:foo, "a"]=>2, [:bar, "b"]=>2, [:foo, "c"]=>2, [:bar, "d"]=>2}
Source
static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
{
VALUE ary = rb_ary_new();
rb_block_call_kw(obj, id_each, argc, argv, collect_all, ary, RB_PASS_CALLED_KEYWORDS);
return ary;
}
Gibt ein Array zurück, das die Elemente von self enthält.
(0..4).to_a # => [0, 1, 2, 3, 4]
Source
static VALUE
enum_to_h(int argc, VALUE *argv, VALUE obj)
{
rb_block_call_func *iter = rb_block_given_p() ? enum_to_h_ii : enum_to_h_i;
return enum_hashify(obj, argc, argv, iter);
}
Wenn self aus 2-elementigen Arrays besteht, wird ein Hash zurückgegeben, dessen Einträge jeweils das Schlüssel-Wert-Paar sind, das aus einem dieser Arrays gebildet wird.
[[:foo, 0], [:bar, 1], [:baz, 2]].to_h # => {:foo=>0, :bar=>1, :baz=>2}
Wenn ein Block gegeben ist, wird der Block mit jedem Element von self aufgerufen; der Block sollte ein 2-elementiges Array zurückgeben, das zu einem Schlüssel-Wert-Paar im zurückgegebenen Hash wird.
(0..3).to_h {|i| [i, i ** 2]} # => {0=>0, 1=>1, 2=>4, 3=>9}
Löst eine Ausnahme aus, wenn ein Element von self kein 2-elementiges Array ist und kein Block übergeben wird.
Source
# File prelude.rb, line 34 def to_set(*args, &block) klass = if args.empty? Set else warn "passing arguments to Enumerable#to_set is deprecated", uplevel: 1 args.shift end klass.new(self, *args, &block) end
Erzeugt ein Set aus dem Enumerable-Objekt mit den gegebenen Argumenten. Das Übergeben von Argumenten an diese Methode ist veraltet.
Source
static VALUE
enum_uniq(VALUE obj)
{
VALUE hash, ret;
rb_block_call_func *const func =
rb_block_given_p() ? uniq_iter : uniq_func;
hash = rb_obj_hide(rb_hash_new());
rb_block_call(obj, id_each, 0, 0, func, hash);
ret = rb_hash_values(hash);
rb_hash_clear(hash);
return ret;
}
Ohne Block wird ein neues Array zurückgegeben, das nur eindeutige Elemente enthält; das Array enthält keine zwei Elemente e0 und e1, sodass e0.eql?(e1) gilt.
%w[a b c c b a a b c].uniq # => ["a", "b", "c"] [0, 1, 2, 2, 1, 0, 0, 1, 2].uniq # => [0, 1, 2]
Mit einem Block wird ein neues Array zurückgegeben, das Elemente enthält, für die der Block nur einen eindeutigen Wert zurückgibt.
a = [0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1] a.uniq {|i| i.even? ? i : 0 } # => [0, 2, 4] a = %w[a b c d e e d c b a a b c d e] a.uniq {|c| c < 'c' } # => ["a", "c"]
Source
static VALUE
enum_zip(int argc, VALUE *argv, VALUE obj)
{
int i;
ID conv;
struct MEMO *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) {
static const VALUE sym_each = STATIC_ID2SYM(id_each);
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 %"PRIsVALUE" (must respond to :each)",
rb_obj_class(argv[i]));
}
argv[i] = rb_funcallv(argv[i], conv, 1, &sym_each);
}
}
if (!rb_block_given_p()) {
result = rb_ary_new();
}
/* TODO: use NODE_DOT2 as memo(v, v, -) */
memo = MEMO_NEW(result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
}
Ohne gegebenen Block wird ein neues Array new_array der Größe self.size zurückgegeben, dessen Elemente Arrays sind. Jedes verschachtelte Array new_array[n] hat die Größe other_enums.size+1 und enthält
-
Das
n-te Element von self. -
Das
n-te Element jedes derother_enums.
Wenn alle other_enums und self die gleiche Größe haben, sind alle Elemente im Ergebnis enthalten und es gibt keine nil-Auffüllung.
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]] f = {foo: 0, bar: 1, baz: 2} g = {goo: 3, gar: 4, gaz: 5} h = {hoo: 6, har: 7, haz: 8} d = f.zip(g, h) d # => [ # [[:foo, 0], [:goo, 3], [:hoo, 6]], # [[:bar, 1], [:gar, 4], [:har, 7]], # [[:baz, 2], [:gaz, 5], [:haz, 8]] # ]
Wenn ein Enumerable in other_enums kleiner als self ist, wird mit nil aufgefüllt bis zur Größe self.size.
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2] c = [:c0, :c1] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
Wenn ein Enumerable in other_enums größer als self ist, werden seine nachfolgenden Elemente ignoriert.
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3, :b4] c = [:c0, :c1, :c2, :c3, :c4, :c5] d = a.zip(b, c) d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
Wenn ein Block gegeben ist, wird der Block mit jedem der Unter-Arrays (wie oben gebildet) aufgerufen; es wird nil zurückgegeben.
a = [:a0, :a1, :a2, :a3] b = [:b0, :b1, :b2, :b3] c = [:c0, :c1, :c2, :c3] a.zip(b, c) {|sub_array| p sub_array} # => nil
Ausgabe
[:a0, :b0, :c0] [:a1, :b1, :c1] [:a2, :b2, :c2] [:a3, :b3, :c3]