Enumerable 모듈
Enumerable 모듈
컬렉션 클래스에 "열거" 능력을 주고 싶을 때, 이 Enumerable 모듈이 가장 먼저 손이 가는 도구예요. 요소를 조회하고, 뽑아내고, 검색하고, 정렬하고, 반복하는 데 유용한 메서드들을 제공하죠.
여기 있는 것들 (What's Here)
Enumerable 모듈이 컬렉션 클래스를 위해 제공하는 메서드를 용도별로 정리하면 이렇게 돼요.
조회 메서드 (Methods for Querying)
요소 자체가 아니라 Enumerable에 대한 정보를 돌려주는 메서드예요:
member?(include?의 별칭):self == object면true, 아니면falseall?: 모든 요소가 기준을 만족하면true, 아니면falseany?: 어떤 요소가 기준을 만족하면true, 아니면falsenone?: 어떤 요소도 기준을 만족하지 않으면true, 아니면falseone?: 정확히 하나의 요소만 기준을 만족하면true, 아니면falsecount: (주어지면) 인자나 블록 기준에 따른 요소의 개수tally: 각 요소의 등장 횟수를 담은 새Hash
가져오는 메서드 (Methods for Fetching)
Enumerable을 수정하지 않고 항목을 돌려주는 메서드예요.
처음·끝·전체 요소:
to_a(entries의 별칭): 모든 요소first: 첫 요소 또는 앞의 요소들take: 지정한 개수의 앞 요소들drop: 지정한 개수의 뒤 요소들take_while: 블록이 시키는 대로 앞 요소들drop_while: 블록이 시키는 대로 뒤 요소들
최소·최대 값 요소:
min:<=>또는 주어진 블록 기준으로 가장 작은 요소max: 가장 큰 요소minmax: 가장 작은 요소와 가장 큰 요소를 담은 2-요소Arraymin_by: 주어진 블록 기준으로 가장 작은 요소max_by: 주어진 블록 기준으로 가장 큰 요소minmax_by: 주어진 블록 기준으로 가장 작고 큰 요소
그룹·슬라이스·분할:
group_by: 요소를 그룹으로 나누는Hashpartition: 블록 기준으로 요소를 두 개의 새 Array로 분할slice_after: 주어진object또는 블록 기준으로self를 분할한 항목들의 새Enumeratorslice_before: 위와 같지만 앞쪽 기준slice_when: 블록 기준으로self를 분할한 항목들의 새Enumeratorchunk: 블록이 시키는 대로 요소를 청크로 조직chunk_while: 블록이 시키는 대로 요소를 청크로 조직
검색·필터 메서드
기준을 만족하는 요소를 돌려주는 메서드예요:
find(detect의 별칭): 블록이 고른 요소find_all(filter,select의 별칭): 블록이 고른 요소들find_index: 주어진 객체 또는 블록이 고른 요소의 인덱스reject: 블록이 거부하지 않은 요소들uniq: 중복되지 않은 요소들
정렬 메서드
정렬된 순서로 요소를 돌려주는 메서드예요:
sort:<=>또는 주어진 블록으로 정렬sort_by: 주어진 블록으로 정렬
반복 메서드
each_entry: 각 연속 요소로 블록 호출 (each와 살짝 다름)each_with_index: 각 연속 요소와 그 인덱스로 블록 호출each_with_object: 각 연속 요소와 주어진 객체로 블록 호출each_slice: 겹치지 않는 연속 슬라이스로 블록 호출each_cons: 겹치는 연속 슬라이스로 블록 호출 (each_slice와 다름)reverse_each: 각 요소를 역순으로 블록 호출
기타 메서드
collect(map의 별칭): 블록이 돌려준 객체들filter_map: 블록이 돌려준 truthy 객체들flat_map(collect_concat의 별칭): 블록이 돌려준 객체들을 펼친 것grep: 주어진 객체로 고른 요소 또는 블록이 돌려준 객체들grep_v: 주어진 객체로 고르지 않은 요소 또는 블록이 돌려준 객체들inject(reduce의 별칭): 모든 요소를 결합해 만든 객체sum:+메서드로 합한 요소의 합zip: 각 요소를 다른 enumerable의 요소와 결합, n-튜플을 돌려주거나 각각으로 블록 호출cycle: 각 요소를 반복해서 블록 호출
사용법 (Usage)
컬렉션 클래스에서 Enumerable 모듈을 쓰려면:
- Include하고:
include Enumerable - 컬렉션의 연속 요소를 내보내는
each메서드를 구현해요.each는 거의 모든Enumerable메서드가 호출하거든요.
예시:
class Foo
include Enumerable
def each
yield 1
yield 1, 2
yield
end
end
Foo.new.each_entry{ |element| p element }
출력:
1
[1, 2]
nil
Ruby 클래스들의 Enumerable
이 Ruby 코어 클래스들이 Enumerable을 include(또는 extend)해요:
ARGF,Array,Dir,Enumerator,ENV(extend),Hash,IO,Range,Struct
이 Ruby 표준 라이브러리 클래스들이 Enumerable을 include해요:
- CSV, CSV::Table, CSV::Row, Set
Enumerable의 거의 모든 메서드는 include한 클래스의 each를 호출해요:
Hash#each는 다음 키-값 쌍을 2-요소Array로 내보내요.Struct#each는 다음 이름-값 쌍을 2-요소Array로 내보내요.- 위의 다른 클래스들에서는
each가 컬렉션의 다음 객체를 내보내요.
확장 메서드 (Extended Methods)
Enumerable 클래스는 확장 메서드를 정의할 수 있어요. 이 섹션은 참고용으로 확장 메서드의 표준 동작을 설명해요.
size
Enumerator는 size 메서드를 갖고 있어요. Enumerator.new에 넘긴 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
size 함수의 결과는 반복 횟수(즉 Enumerator::Yielder#yield가 호출되는 횟수)를 나타내야 해요. 위 예시에서 블록은 yield를 세 번 호출하고, size 함수 -> { 3 }이 그에 맞게 3을 돌려줘요. size 함수 결과는 정수, Float::INFINITY, nil 중 하나일 수 있어요. 정수는 yield가 호출될 정확한 횟수, Float::INFINITY는 무한 횟수, nil은 결정하기 어렵거나 불가능함을 뜻해요.
많은 반복 메서드는 블록을 주지 않으면 적절한 size 함수를 가진 Enumerator 객체를 돌려줘요.
["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
Range 기반 enumerator의 size 동작은 begin 요소에 따라 달라요:
- begin 요소가
Integer면 size는Integer또는Float::INFINITY를 돌려줘요. - begin 요소가 succ 메서드를 가진(
Integer가 아닌) 객체면 size는nil을 돌려줘요. (크기를 계산하려면 succ를 반복 호출해야 해서 너무 느릴 수 있어요.) - begin 요소가 succ 메서드가 없으면 size는
TypeError를 던져요.
(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)
Enumerable 모듈 자체는 size 메서드를 정의하지 않아요. include한 클래스가 자신만의 size 메서드를 정의할 수 있는데, 그런 size 메서드는 Enumerator#size와 일관성이 있는 게 좋아요. Array와 Hash는 Enumerator#size와 일치하는 size를 구현해요. IO와 Dir은 size를 정의하지 않는데, 대응하는 enumerator의 size 함수가 nil을 돌려주므로 이것도 일관돼요. 다만 클래스의 size 메서드가 반드시 Enumerator#size와 일치해야 하는 건 아니에요. 예를 들어 File#size는 파일의 줄 수가 아니라 바이트 수를 돌려줘요.
인스턴스 메서드
-
all? → true or false— 모든 요소가 주어진 기준을 만족하는지 돌려줘요.self에 요소가 없으면true를 돌려주고 인자·블록은 쓰지 않아요. 인자와 블록 없이 호출하면 모든 요소가 truthy인지 돌려줘요.(1..4).all? # => true [1, 2, nil].all? # => false [].all? # => true패턴 인자와 블록 없이 호출하면 각 요소에 대해
pattern === element인지 돌려줘요:(1..4).all?(Integer) # => true %w[bar baz bat bam].all?(/ba/) # => true [].all?(Integer) # => true블록을 주면 모든 요소에 대해 블록이 truthy 값을 돌려주는지 돌려줘요:
(1..4).all? {|element| element < 5 } # => true {foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 3 } # => true관련:
any?,none?,one?. -
any? → true or false— 어떤 요소가 주어진 기준을 만족하는지 돌려줘요.self에 요소가 없으면false를 돌려줘요. 인자·블록 없이 호출하면 어떤 요소가 truthy인지:[1, false, nil].any? # => true,[].any? # => false. 패턴 인자와 함께:[nil, false, 0].any?(Integer) # => true. 블록과 함께:(1..4).any? {|element| element < 2 } # => true. 관련:all?,none?,one?. -
chain(*enums) → enumerator— 이 enumerator와 주어진 enumerable들로 만든 enumerator 객체를 돌려줘요.e = (1..3).chain([4, 5]) e.to_a #=> [1, 2, 3, 4, 5] -
chunk {|array| ... } → enumerator— 돌려줄 enumerator의 각 요소는 2-요소 배열이에요: (블록이 돌려준 값, 그 값이 나온 요소와 이후 블록이 같은 값을 돌려준 모든 요소로 이뤄진 "청크" 배열). 즉 이전 값과 다른 블록 반환값은 새 청크를 시작하고, 이전 값과 같은 반환값은 같은 청크를 이어가요.e = (0..10).chunk {|i| (i / 3).floor } # => #<Enumerator: ...> e.next # => [0, [0, 1, 2]] e.next # => [1, [3, 4, 5]] e.next # => [2, [6, 7, 8]] e.next # => [3, [9, 10]]특수 심볼
:_alone을 쓰면 요소를 자기만의 별도 청크로 강제할 수 있어요:a = [0, 0, 1, 1] e = a.chunk{|i| i.even? ? :_alone : true } e.to_a # => [[:_alone, [0]], [:_alone, [0]], [true, [1, 1]]]특수 심볼
:_separator또는nil을 쓰면 요소를 무시(어떤 청크에도 포함하지 않음)하도록 강제할 수 있어요:a = [0, 0, -1, 1, 1] e = a.chunk{|i| i < 0 ? :_separator : true } e.to_a # => [[true, [0, 0]], [true, [1, 1]]]separated는 청크를 끝낸다는 점에 주의하세요.
-
chunk_while {|elt_before, elt_after| bool } → an_enumerator— 각 청크된 요소들에 대한 enumerator를 만들어요. 청크의 시작은 블록이 정의해요. 인접 요소 elt_before와 elt_after 사이를, 블록이false를 돌려주는 지점에서 나눠요. 블록은 receiver enumerator 길이 - 1번 호출돼요. 결과 enumerator는 청크된 요소들을 배열로 내보내요.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"인접한 짝수·홀수도 청크할 수 있어요:
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은 블록이true를 돌려주는 지점에서 나눈다는 점만 빼고 같아요. -
compact → array—nil이 아닌 모든 요소의 배열을 돌려줘요:[nil, 0, nil, 'a'].compact # => [0, "a"] -
count → integer— (주어지면) 인자나 블록 기준에 따른 요소 개수를 돌려줘요. 인자·블록 없이: 요소 개수.object인자:==로 같은 요소 개수. 블록: truthy를 돌려주는 요소 개수.[0, 1, 2].count # => 3 [0, 1, 2, 1].count(1) # => 2 [0, 1, 2, 3].count {|element| element < 2} # => 2 -
cycle(n = nil) {|element| ...} → nil— 양의 정수 인자n과 블록과 함께 호출하면, 각 요소로n번 블록을 호출하고nil을 돌려줘요. count가 0이거나 음수면 블록을 호출하지 않아요.n이nil이면 무한히 돌려요. 블록이 없으면Enumerator를 돌려줘요.a = [] (1..4).cycle(3) {|element| a.push(element) } # => nil a # => [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4] -
drop(n) → array— 양의 정수n에 대해 첫n개 요소를 제외한 모두를 담은 배열을 돌려줘요:(1..4).drop(3) # => [4],(1..4).drop(50) # => [] -
drop_while {|element| ... } → array— 블록이 truthy를 돌려주는 동안 연속 요소로 블록을 호출하고, 그 이후의 모든 요소 배열을 돌려줘요:(1..4).drop_while{|i| i < 3 } # => [3, 4]. 블록이 없으면Enumerator를 돌려줘요. -
each_cons(n) { ... } → self— 각 연속되는 겹치는n-튜플 요소로 블록을 호출하고self를 돌려줘요.a = [] (1..5).each_cons(3) {|element| a.push(element) } a # => [[1, 2, 3], [2, 3, 4], [3, 4, 5]] -
each_entry(*args) {|element| ... } → self— yield에서 여러 값을 배열로 변환하면서 각 요소로 주어진 블록을 호출하고self를 돌려줘요. 블록이 없으면Enumerator를 돌려줘요.a = [] (1..4).each_entry {|element| a.push(element) } # => 1..4 a # => [1, 2, 3, 4] -
each_slice(n) { ... } → self— 각 연속되는 겹치지 않는n-튜플 요소로 블록을 호출하고self를 돌려줘요:(1..10).each_slice(3) {|tuple| a.push(tuple) }. 블록이 없으면Enumerator를 돌려줘요. -
each_with_index(*args) {|element, i| ... } → self—*args로self.each를 호출해요. 블록을 주면 각 요소와 그 인덱스를 받아요. 블록이 없으면Enumerator를 돌려줘요.h = {} (1..4).each_with_index {|element, i| h[element] = i } # => 1..4 h # => {1=>0, 2=>1, 3=>2, 4=>3} -
each_with_object(object) { |(*args), memo_object| ... } → object— 각 요소마다 객체와 함께 블록을 한 번씩 호출하고object를 돌려줘요.(1..4).each_with_object([]) {|i, a| a.push(i**2) } # => [1, 4, 9, 16] -
filter_map {|element| ... } → array— 블록이 돌려준 truthy 요소들을 담은 배열을 돌려줘요.(0..9).filter_map {|i| i * 2 if i.even? } # => [0, 4, 8, 12, 16] -
find(if_none_proc = nil) {|element| ... } → object or nil— 블록이 truthy를 돌려주는 첫 요소를 돌려줘요. 발견하지 못하면if_none_proc을 호출하고 그 반환값을 돌려줘요. 블록이 없으면Enumerator를 돌려줘요.(0..9).find {|element| element > 2} # => 3 (0..9).find(proc {false}) {|element| element > 12} # => false -
find_index(object) → integer or nil— 지정된 기준을 만족하는 첫 요소의 인덱스를 돌려주거나, 없으면nil을 돌려줘요.object인자:==인 첫 요소의 인덱스. 블록: truthy를 돌려주는 첫 요소의 인덱스. 인자·블록 없이:Enumerator.['a', 'b', 'c', 'b'].find_index('b') # => 1 -
first → element or nil— 첫 요소를 돌려주거나, 없으면nil. 정수n과 함께: 존재하는 첫n개 요소를 담은 배열.(1..4).first # => 1 (1..4).first(2) # => [1, 2] [].first # => nil -
flat_map {|element| ... } → array— 블록이 돌려준 객체들을 펼친 배열을 돌려줘요. (collect_concat의 별칭)[0, 1, 2, 3].flat_map {|element| [element, -element] } # => [0, 0, 1, -1, 2, -2, 3, -3] -
grep(pattern) → array— 주어진 패턴과 일치하는 요소 기반 객체 배열을 돌려줘요. 블록 없이:pattern === element가 true인 각 요소. 블록과 함께: 각 일치 요소로 블록을 호출하고 반환된 각 객체를 담은 배열.a = ['foo', 'bar', 'car', 'moo'] a.grep(/ar/) # => ["bar", "car"] a.grep(/ar/) {|element| element.upcase } # => ["BAR", "CAR"]grep_v는 반대예요 (
pattern === element가 false인 요소). -
group_by {|element| ... } → hash— 블록과 함께 호출하면 해시를 돌려줘요. 각 키는 블록 반환값, 각 값은 그 키를 돌려준 요소들의 배열.g = (1..6).group_by {|i| i%3 } g # => {1=>[1, 4], 2=>[2, 5], 0=>[3, 6]} -
include?(object) → true or false— 어떤 요소에 대해object == element인지.(1..4).include?(2) # => true (1..4).include?(5) # => false -
inject(symbol) → object— 감소기(reducer)를 초기값과Enumerable의 첫 요소에 적용한 결과를 돌려줘요.[ a, b, c, d ].inject(i) { |r, v| fn(r, v) }는fn(fn(fn(fn(i, a), b), c), d)로 생각하면 돼요.inject는reduce로도 불려요. 호출 시퀀스: 가장 장황한 형태는enum.inject(initial_value) do |result, next_value| ... end예요.product = [ 2, 3, 4 ].inject(1) do |result, next_value| result * next_value end product #=> 24첫 번째 단축키: 기본 초기값: 초기값을 생략하면
inject는 첫 요소를result, 둘째 요소를next_value로 블록을 호출해요. 단, 블록 결과가 다시 첫 인자로 넘겨질 수 있을 때만 쓸 수 있어요:[ 2, 3, 4 ].inject do |result, next_value| result * next_value end두 번째 단축키: 감소기 함수:
inject에 감소기 함수의 이름(심볼)을 넘길 수 있어요. 그 함수는 결과 값 타입에 정의돼 있어야 하고, 컬렉션의 다음 값을 단일 인자로 받으며, 갱신된 결과를 돌려줘야 해요.s = [ "cat", " ", "dog" ].inject("", :concat) s #=> "cat dog" s = [ "cat", " ", "dog" ].inject("The result is:", :+) s #=> "The result is: cat dog"세 번째 단축키: 초기값 없는 감소기: 감소기가 자신을 받아들일 수 있는 값을 돌려주면 초기값을 넘기지 않아도 돼요:
product = [ 2, 3, 4 ].inject(:*) product # => 24 nested = {foo: 0, bar: 1}.inject([], :push) nested # => [[:foo, 0], [:bar, 1]] -
lazy → lazy_enumerator—Enumerator::Lazy를 돌려줘요. 대부분의Enumerable메서드를 재정의해 열거를 연기하고, 필요할 때만 값을 열거해요.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 p pythagorean_triples.take(10).force # take is lazy, so force is needed p pythagorean_triples.first(10) # first is eager -
map {|element| ... } → array— 블록이 돌려준 객체들의 배열을 돌려줘요. 블록이 없으면Enumerator.(0..4).map {|i| i*i } # => [0, 1, 4, 9, 16] -
max → element— 주어진 기준에 따른 최대 요소를 돌려줘요. 같은 값의 순서는 결정적이지 않고 불안정할 수 있어요. 인자·블록 없이<=>로 비교. 정수n과 함께: 존재하는 첫n개 최대 요소. 블록: 두 요소a,b로 호출되어a<b면 음수,a==b면 0,a>b면 양수를 돌려줘야 해요.(1..4).max # => 4 (1..4).max(2) # => [4, 3] %w[xxx x xxxx xx].max {|a, b| a.size <=> b.size } # => "xxxx"관련:
min,minmax,max_by. -
max_by {|element| ... } → element— 블록이 최대 값을 돌려주는 요소를 돌려줘요. 정수n과 함께: 블록이 최대 값을 돌려주는n개 요소를 담은 배열. 블록 없이Enumerator. -
min → element— 최소 요소. 관련:min_by,minmax,max.(1..4).min # => 1 (1..4).min(2) # => [1, 2] %w[xxx x xxxx xx].min {|a, b| a.size <=> b.size } # => "x" -
min_by {|element| ... } → element— 블록이 최소 값을 돌려주는 요소.n과 함께: 최소 값의n개 요소 배열. -
minmax → [minimum, maximum]— 최소·최대 요소를 담은 2-요소 배열. 관련:min,max,minmax_by. -
minmax_by {|element| ... } → [minimum, maximum]— 블록이 최소·최대 값을 돌려주는 요소들을 담은 2-요소 배열. -
none? → true or false— 어떤 요소도 주어진 기준을 만족하지 않는지. 인자·블록 없이: truthy인 요소가 없는지. 패턴:pattern === element인 요소가 없는지. 블록: truthy를 돌려주는 요소가 없는지. 관련:one?,all?,any?. -
one? → true or false— 정확히 하나의 요소만 기준을 만족하는지. 관련:none?,all?,any?. -
partition {|element| ... } → [true_array, false_array]— 두 배열로 이뤄진 배열을 돌려줘요. 첫 번째는 블록이 truthy를 돌려주는 요소들, 다른 하나는 나머지 전부.p = (1..4).partition {|i| i.even? } p # => [[2, 4], [1, 3]] -
reject {|element| ... } → array— 블록이 거부한 객체들의 배열을 돌려줘요 (블록이nil또는false를 돌려주는 요소들). 블록 없이Enumerator. 관련:select. -
reverse_each(*args) {|element| ... } → self— 각 요소를 역순으로 블록 호출하고self를 돌려줘요. 블록 없이Enumerator.a = [] (1..4).reverse_each {|element| a.push(-element) } # => 1..4 a # => [-4, -3, -2, -1] -
select {|element| ... } → array— 블록이 고른 요소들을 담은 배열. 관련:reject.(0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9] -
slice_after(pattern) → an_enumerator— 각 청크된 요소들에 대한 enumerator를 만들어요. 청크의 끝은 pattern과 블록이 정의해요.pattern === elt또는 블록이 그 요소에 대해 true를 돌려주면 그 요소가 청크의 끝이에요.===와 block은 enum의 첫 요소부터 마지막 요소까지 호출돼요. 결과 enumerator는 청크된 요소들을 배열로 내보내요.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"]] -
slice_before(pattern) → enumerator— pattern 인자와 함께, 패턴이 요소들을 배열("슬라이스")로 분할하는 데 쓰이는 enumerator를 돌려줘요.element === pattern(또는 첫 요소)이면 그 요소가 새 슬라이스를 시작해요. 블록과 함께: 블록 반환값이 truthy(또는 첫 요소)이면 새 슬라이스.a = %w[foo bar fop for baz fob fog bam foy] e = a.slice_before(/ba/) # => #<Enumerator: ...> e.each {|array| p array }출력:
["foo"] ["bar", "fop", "for"] ["baz", "fob", "fog"] ["bam", "foy"] -
slice_when {|elt_before, elt_after| bool } → an_enumerator— 각 청크된 요소들에 대한 enumerator. 청크 시작은 블록이 정의해요. 인접 요소 사이를, 블록이true를 돌려주는 지점에서 나눠요.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]]chunk_while은 블록이false를 돌려주는 지점에서 나눈다는 점만 빼고 같아요. -
sort → array—self의 정렬된 요소를 담은 배열을 돌려줘요. 블록 없이: 요소 자신의<=>로 비교. 블록: 두 요소a,b로 호출되어 순서를 결정. 관련sort_by는 Schwartzian transform을 구현하며 키 계산이나 비교가 비쌀 때 유용해요.%w[b c a d].sort # => ["a", "b", "c", "d"] a = %w[b c a d] a.sort {|a, b| b <=> a } # => ["d", "c", "b", "a"] -
sort_by {|element| ... } → array— 블록이 각 요소에 대해 돌려준 값에 따라 정렬된self의 요소 배열을 돌려줘요.sort_by는 원래 컬렉션 요소와 매핑된 값을 담은 튜플 배열을 만들기 때문에, 키셋이 단순할 때는 꽤 비싸요.ary.sort_by { ... }.reverse!로 특정 순서의 역순을 만들 수 있어요. -
sum(initial_value = 0) → number— 블록 없이:initial_value와 요소들의 합. 블록과 함께:initial_value와 블록 반환값들의 합. 가능하면 가우스 합 공식 n(n+1)/2로 계산해요.(1..100).sum # => 5050 (1..100).sum(1) # => 5051 ('a'..'d').sum('foo') # => "fooabcd" (1..4).sum {|i| i*i } # => 30 -
take(n) → array— 음이 아닌 정수n에 대해 첫n개 요소.(1..4).take(2) # => [1, 2] (1..4).take(0) # => [] -
take_while {|element| ... } → array— 블록이 truthy를 돌려주는 동안 연속 요소로 블록을 호출하고, 그 시점까지의 모든 요소 배열을 돌려줘요:(1..4).take_while{|i| i < 3 } # => [1, 2]. 블록 없이Enumerator. -
tally(hash = {}) → hash—hash인자가 없으면:self의 고유 요소를 키로, 각 요소의 등장 횟수를 정수 값으로 하는 새 해시를 돌려줘요.hash인자를 주면 그hash를 (가능하면) 보강해 돌려줘요. 각 요소에 대해 키가 없으면 값 0으로 추가하고 값을 1 증가시켜요. 여러 enumerable에 걸쳐 합산을 누적할 때 유용해요.%w[a b c b c a c b].tally # => {"a"=>2, "b"=>3, "c"=>3} 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} -
to_a(*args) → array—self의 항목들을 담은 배열을 돌려줘요:(0..4).to_a # => [0, 1, 2, 3, 4] -
to_h(*args) → hash—self가 2-요소 배열로 이뤄져 있으면, 각 배열이 만드는 키-값 쌍의 해시를 돌려줘요. 블록을 주면 그 블록이 2-요소 배열을 돌려줘야 해요. 요소가 2-요소 배열이 아니고 블록도 없으면 예외.[[:foo, 0], [:bar, 1], [:baz, 2]].to_h # => {:foo=>0, :bar=>1, :baz=>2} (0..3).to_h {|i| [i, i ** 2]} # => {0=>0, 1=>1, 2=>4, 3=>9} -
uniq → array— 블록 없이:e0.eql?(e1)인 두 요소가 없는, 고유 요소만 담은 새 배열. 블록: 블록이 고유한 값을 돌려주는 요소만 담은 새 배열.%w[a b c c b a a b c].uniq # => ["a", "b", "c"] a = [0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1] a.uniq {|i| i.even? ? i : 0 } # => [0, 2, 4] -
zip(*other_enums) → array— 블록 없이,self.size크기의 새 배열new_array를 돌려줘요. 각 요소는 크기가other_enums.size+1인 배열이며self의 n번째 요소와 각 other_enum의 n번째 요소를 담아요. 다른 enumerable이 더 작으면self.size까지nil로 채우고, 더 크면 뒤 요소를 무시해요. 블록과 함께: 각 하위 배열로 블록 호출하고 nil을 돌려줘요.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]]