(1..10).find { |i| i % 3 = 0 }   
#=> 3

('a'..'z').find { |c| c == "Z" }  
#=> nil

(1..10).find(-> {"Not Found"}) { |i| i > 15 } 
#=> "Not Found"

Find изпълнява блока на всеки елемент от колекцията на свой ред. Връща първия елемент, който прави блока верен. Има незадължителен аргумент ifnone, който се извиква, ако никой елемент не прави блока верен. В третия пример по-горе използвам синтаксис stabby-proc, за да върна „Не е намерено“ в този случай. Find е псевдоним като detect.

избери

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

{a: 1, b: 2, c: 3, d: 4}.select { |k, v| v % 2 == 0} 
#=> {:b=>2, :d=>4}

Подобно на find, select изпълнява блока на всеки елемент от колекцията. Вместо да спре първия път, когато блокът върне true, select продължава и връща всички стойности, които правят блока true. Както всички изброими методи select може да се използва за масиви, хешове, диапазони, набори и всеки друг клас освен миксове в модула Enumerable. Select може да се извика и с find_all.

отхвърлям

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

{a: 1, b: 2, c: 3, d: 4}.reject { |k, v| v % 2 == 0} 
#=> {:a=>1, :c=>3}

Отхвърлянето е обратното на избора. Той изпълнява блока на всеки елемент на свой ред и връща онези, при които блокът оценява на false.

"всичко?" някакви? един? "нито един?"

(1..5).all? { |i| i < 6}  #=> true
(1..5).all? { |i| i < 2}  #=> false

(1..5).any? { |i| i < 2}  #=> true

(1..5).one? { |i| i < 2}  #=> true

(1..5).none? { |i| i < 5} #=> false

Използвах цикли с each, while или until, за да ги внедря. Научаването, че те са вградени в enumerable, ме прави по-малко податлив на грешки. По конвенцията на Ruby всички те завършват с въпросителен знак и затова са предикатни методи; те връщат или истина, или невярно. Всичко? връща true само ако блокът върне true за всеки елемент в колекцията. Някакви? предава елемент към блока на свой ред. Когато даден елемент прави блока верен, извикването на any? връща true и останалите елементи в колекцията не се проверяват. В следния пример е отпечатана само една звезда.

(1..5).any? { |i| puts "*"; i < 2}
*
#=> true

един? връща true тогава и само ако точно един елемент кара блока да връща true. Той се връща, когато всички елементи са проверени или когато за първи път открие два елемента, които правят блока верен.

(1..5).one? { |i| puts "*"; i < 3}
*
*
#=> false

И накрая, нито един? връща true, ако никой от елементите в блока не прави колекцията true. Ще се върне по-рано, ако даден елемент направи блока верен. В противен случай трябва да оцени всички елементи в колекцията.

"Групирай по"

(1..6).group_by { |i| i.even? }
#=>  {false=>[1, 3, 5], true=>[2, 4, 6]}

{a: 1, b: 3, c: 3, d: 2, e: 1}.group_by { |_, k| k }
#=> {1=>[[:a, 1], [:e, 1]], 3=>[[:b, 3], [:c, 3]], 2=>[[:d, 2]]}

Group_by предава всеки елемент от колекцията към блока и връща хеш, където ключовете са върнати стойности от блока, а стойностите са списък с елементи, които са накарали блока да оцени тази стойност.

Когато се изпълнява срещу хеш, това връща оставени кортежи вместо хеш като стойности. За да конвертирате кортежите обратно в хеш, можете да използвате метода на класа Hash::[].

hsh = {1=>[[:a, 1], [:e, 1]], 3=>[[:b, 3], [:c, 3]], 2=>[[:d, 2]]}

hsh.each { |k, v| hsh[k] = Hash[v] }

#=> {1=>{:a=>1, :e=>1}, 3=>{:b=>3, :c=>3}, 2=>{:d=>2}}

всяки_против

(1..5).each_cons(2) { |a| p a }

# outputs below
[1, 2]
[2, 3]
[3, 4]
[4, 5]

Every_cons изпълнява плъзгащ се прозорец върху колекцията. Аргументът към each_cons е размерът на прозореца и стойностите в прозореца се предават на блока. За хората, които си спомниха да го използват, това беше удобно по време на упражнението на веригата Марков на Seattle.rb. Можете или да третирате стойностите като една променлива (както направих по-горе), или можете да ги разглобите, както по-долу.

(1..8).each_cons(4) { |a, _, _, d| p "#{a}, #{d}" }

# outputs below
"1, 4"
"2, 5"
"3, 6"
"4, 7"
"5, 8"

Всеки елемент, който each_cons използва в блока, ще съдържа същия брой елементи. Няма да има частичен „прозорец“, изпратен до блока.

всяко_филче

%w[a b c d e].each_slice(2) { |a| p a }

# outputs below
["a", "b"]
["c", "d"]
["e"]

Това е още един, който прекарах няколко часа да прилагам на ръка, преди някой да ме насочи към вградената версия. Опитвах се да изобразя решетка от елементи в Rails. Всеки ред имаше пет елемента, а последният ред можеше да има по-малко в зависимост от общия брой. Имах два или три вложени цикъла, за да го направя. Every_slice е много по-чист. За разлика от each_cons, each_slice може да върне „частичен прозорец“, ако колекцията не се дели равномерно от аргумента, подаден на всеки срез.

Изброим е твой приятел

Има много повече в enumerable, които могат да бъдат полезни. За мен enumerable е чудесен пример за философията на Ruby, че програмирането трябва да бъде забавно. Много от обичайните неща, които искате да правите с колекциите, се включват автоматично. Още по-добре, ако включите модула Enumerable, обектите на вашата колекция също получават тези методи.

Първоначално публикувано на Thagomizer — Spikes of Destiny