938 lines
24 KiB
Ruby
Vendored
938 lines
24 KiB
Ruby
Vendored
##
|
|
# Enumerable
|
|
#
|
|
module Enumerable
|
|
##
|
|
# call-seq:
|
|
# enum.drop(n) -> array
|
|
#
|
|
# Drops first n elements from *enum*, and returns rest elements
|
|
# in an array.
|
|
#
|
|
# a = [1, 2, 3, 4, 5, 0]
|
|
# a.drop(3) #=> [4, 5, 0]
|
|
|
|
def drop(n)
|
|
n = n.__to_int
|
|
raise ArgumentError, "attempt to drop negative size" if n < 0
|
|
|
|
ary = []
|
|
self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 }
|
|
ary
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.drop_while {|arr| block } -> array
|
|
# enum.drop_while -> an_enumerator
|
|
#
|
|
# Drops elements up to, but not including, the first element for
|
|
# which the block returns `nil` or `false` and returns an array
|
|
# containing the remaining elements.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# a = [1, 2, 3, 4, 5, 0]
|
|
# a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0]
|
|
|
|
def drop_while(&block)
|
|
return to_enum(:drop_while) unless block
|
|
|
|
ary, state = [], false
|
|
self.each do |*val|
|
|
state = true if !state and !block.call(*val)
|
|
ary << val.__svalue if state
|
|
end
|
|
ary
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.take(n) -> array
|
|
#
|
|
# Returns first n elements from *enum*.
|
|
#
|
|
# a = [1, 2, 3, 4, 5, 0]
|
|
# a.take(3) #=> [1, 2, 3]
|
|
|
|
def take(n)
|
|
n = n.__to_int
|
|
i = n.to_i
|
|
raise ArgumentError, "attempt to take negative size" if i < 0
|
|
ary = []
|
|
return ary if i == 0
|
|
self.each do |*val|
|
|
ary << val.__svalue
|
|
i -= 1
|
|
break if i == 0
|
|
end
|
|
ary
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.take_while {|arr| block } -> array
|
|
# enum.take_while -> an_enumerator
|
|
#
|
|
# Passes elements to the block until the block returns `nil` or `false`,
|
|
# then stops iterating and returns an array of all prior elements.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# a = [1, 2, 3, 4, 5, 0]
|
|
# a.take_while {|i| i < 3 } #=> [1, 2]
|
|
#
|
|
def take_while(&block)
|
|
return to_enum(:take_while) unless block
|
|
|
|
ary = []
|
|
self.each do |*val|
|
|
return ary unless block.call(*val)
|
|
ary << val.__svalue
|
|
end
|
|
ary
|
|
end
|
|
|
|
##
|
|
# Iterates the given block for each array of consecutive <n>
|
|
# elements.
|
|
#
|
|
# @return [nil]
|
|
#
|
|
# @example
|
|
# (1..10).each_cons(3) {|a| p a}
|
|
# # outputs below
|
|
# [1, 2, 3]
|
|
# [2, 3, 4]
|
|
# [3, 4, 5]
|
|
# [4, 5, 6]
|
|
# [5, 6, 7]
|
|
# [6, 7, 8]
|
|
# [7, 8, 9]
|
|
# [8, 9, 10]
|
|
|
|
def each_cons(n, &block)
|
|
n = n.__to_int
|
|
raise ArgumentError, "invalid size" if n <= 0
|
|
|
|
return to_enum(:each_cons,n) unless block
|
|
ary = []
|
|
n = n.to_i
|
|
self.each do |*val|
|
|
ary.shift if ary.size == n
|
|
ary << val.__svalue
|
|
block.call(ary.dup) if ary.size == n
|
|
end
|
|
nil
|
|
end
|
|
|
|
##
|
|
# Iterates the given block for each slice of <n> elements.
|
|
#
|
|
# @return [nil]
|
|
#
|
|
# @example
|
|
# (1..10).each_slice(3) {|a| p a}
|
|
# # outputs below
|
|
# [1, 2, 3]
|
|
# [4, 5, 6]
|
|
# [7, 8, 9]
|
|
# [10]
|
|
|
|
def each_slice(n, &block)
|
|
n = n.__to_int
|
|
raise ArgumentError, "invalid slice size" if n <= 0
|
|
|
|
return to_enum(:each_slice,n) unless block
|
|
ary = []
|
|
n = n.to_i
|
|
self.each do |*val|
|
|
ary << val.__svalue
|
|
if ary.size == n
|
|
block.call(ary)
|
|
ary = []
|
|
end
|
|
end
|
|
block.call(ary) unless ary.empty?
|
|
nil
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.group_by {| obj | block } -> a_hash
|
|
# enum.group_by -> an_enumerator
|
|
#
|
|
# Returns a hash, which keys are evaluated result from the
|
|
# block, and values are arrays of elements in *enum*
|
|
# corresponding to the key.
|
|
#
|
|
# (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
|
|
#
|
|
def group_by(&block)
|
|
return to_enum(:group_by) unless block
|
|
|
|
h = {}
|
|
self.each do |*val|
|
|
key = block.call(*val)
|
|
sv = val.__svalue
|
|
h.key?(key) ? (h[key] << sv) : (h[key] = [sv])
|
|
end
|
|
h
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.sort_by { |obj| block } -> array
|
|
# enum.sort_by -> an_enumerator
|
|
#
|
|
# Sorts *enum* using a set of keys generated by mapping the
|
|
# values in *enum* through the given block.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
def sort_by(&block)
|
|
return to_enum(:sort_by) unless block
|
|
self.to_a.sort_by(&block)
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.first -> obj or nil
|
|
# enum.first(n) -> an_array
|
|
#
|
|
# Returns the first element, or the first `n` elements, of the enumerable.
|
|
# If the enumerable is empty, the first form returns `nil`, and the
|
|
# second form returns an empty array.
|
|
def first(*args)
|
|
case args.length
|
|
when 0
|
|
self.each do |*val|
|
|
return val.__svalue
|
|
end
|
|
return nil
|
|
when 1
|
|
i = args[0].__to_int
|
|
raise ArgumentError, "attempt to take negative size" if i < 0
|
|
ary = []
|
|
return ary if i == 0
|
|
self.each do |*val|
|
|
ary << val.__svalue
|
|
i -= 1
|
|
break if i == 0
|
|
end
|
|
ary
|
|
else
|
|
raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)"
|
|
end
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.count -> int
|
|
# enum.count(item) -> int
|
|
# enum.count { |obj| block } -> int
|
|
#
|
|
# Returns the number of items in `enum` through enumeration.
|
|
# If an argument is given, the number of items in `enum` that
|
|
# are equal to `item` are counted. If a block is given, it
|
|
# counts the number of elements yielding a true value.
|
|
def count(v=NONE, &block)
|
|
count = 0
|
|
if block
|
|
self.each do |*val|
|
|
count += 1 if block.call(*val)
|
|
end
|
|
else
|
|
if NONE.equal?(v)
|
|
self.each { count += 1 }
|
|
else
|
|
self.each do |*val|
|
|
count += 1 if val.__svalue == v
|
|
end
|
|
end
|
|
end
|
|
count
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.flat_map { |obj| block } -> array
|
|
# enum.collect_concat { |obj| block } -> array
|
|
# enum.flat_map -> an_enumerator
|
|
# enum.collect_concat -> an_enumerator
|
|
#
|
|
# Returns a new array with the concatenated results of running
|
|
# <em>block</em> once for every element in *enum*.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# [1, 2, 3, 4].flat_map { |e| [e, -e] } #=> [1, -1, 2, -2, 3, -3, 4, -4]
|
|
# [[1, 2], [3, 4]].flat_map { |e| e + [100] } #=> [1, 2, 100, 3, 4, 100]
|
|
def flat_map(&block)
|
|
return to_enum(:flat_map) unless block
|
|
|
|
ary = []
|
|
self.each do |*e|
|
|
e2 = block.call(*e)
|
|
if e2.respond_to?(:each)
|
|
e2.each {|e3| ary.push(e3) }
|
|
else
|
|
ary.push(e2)
|
|
end
|
|
end
|
|
ary
|
|
end
|
|
alias collect_concat flat_map
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.max_by {|obj| block } -> obj
|
|
# enum.max_by -> an_enumerator
|
|
#
|
|
# Returns the object in *enum* that gives the maximum
|
|
# value from the given block.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# %w[albatross dog horse].max_by {|x| x.length } #=> "albatross"
|
|
|
|
def max_by(&block)
|
|
return to_enum(:max_by) unless block
|
|
|
|
first = true
|
|
max = nil
|
|
max_cmp = nil
|
|
|
|
self.each do |*val|
|
|
if first
|
|
max = val.__svalue
|
|
max_cmp = block.call(*val)
|
|
first = false
|
|
else
|
|
if (cmp = block.call(*val)) > max_cmp
|
|
max = val.__svalue
|
|
max_cmp = cmp
|
|
end
|
|
end
|
|
end
|
|
max
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.min_by {|obj| block } -> obj
|
|
# enum.min_by -> an_enumerator
|
|
#
|
|
# Returns the object in *enum* that gives the minimum
|
|
# value from the given block.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# %w[albatross dog horse].min_by {|x| x.length } #=> "dog"
|
|
|
|
def min_by(&block)
|
|
return to_enum(:min_by) unless block
|
|
|
|
first = true
|
|
min = nil
|
|
min_cmp = nil
|
|
|
|
self.each do |*val|
|
|
if first
|
|
min = val.__svalue
|
|
min_cmp = block.call(*val)
|
|
first = false
|
|
else
|
|
if (cmp = block.call(*val)) < min_cmp
|
|
min = val.__svalue
|
|
min_cmp = cmp
|
|
end
|
|
end
|
|
end
|
|
min
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.minmax -> [min, max]
|
|
# enum.minmax { |a, b| block } -> [min, max]
|
|
#
|
|
# Returns two elements array which contains the minimum and the
|
|
# maximum value in the enumerable. The first form assumes all
|
|
# objects implement `Comparable`; the second uses the
|
|
# block to return <em>a <=> b</em>.
|
|
#
|
|
# a = %w(albatross dog horse)
|
|
# a.minmax #=> ["albatross", "horse"]
|
|
# a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"]
|
|
|
|
def minmax(&block)
|
|
max = nil
|
|
min = nil
|
|
first = true
|
|
|
|
self.each do |*val|
|
|
if first
|
|
val = val.__svalue
|
|
max = val
|
|
min = val
|
|
first = false
|
|
else
|
|
val = val.__svalue
|
|
if block
|
|
max = val if block.call(val, max) > 0
|
|
min = val if block.call(val, min) < 0
|
|
else
|
|
max = val if (val <=> max) > 0
|
|
min = val if (val <=> min) < 0
|
|
end
|
|
end
|
|
end
|
|
[min, max]
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.minmax_by { |obj| block } -> [min, max]
|
|
# enum.minmax_by -> an_enumerator
|
|
#
|
|
# Returns a two element array containing the objects in
|
|
# *enum* that correspond to the minimum and maximum values respectively
|
|
# from the given block.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# %w(albatross dog horse).minmax_by { |x| x.length } #=> ["dog", "albatross"]
|
|
|
|
def minmax_by(&block)
|
|
return to_enum(:minmax_by) unless block
|
|
|
|
max = nil
|
|
max_cmp = nil
|
|
min = nil
|
|
min_cmp = nil
|
|
first = true
|
|
|
|
self.each do |*val|
|
|
if first
|
|
max = min = val.__svalue
|
|
max_cmp = min_cmp = block.call(*val)
|
|
first = false
|
|
else
|
|
if (cmp = block.call(*val)) > max_cmp
|
|
max = val.__svalue
|
|
max_cmp = cmp
|
|
end
|
|
if (cmp = block.call(*val)) < min_cmp
|
|
min = val.__svalue
|
|
min_cmp = cmp
|
|
end
|
|
end
|
|
end
|
|
[min, max]
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.none? [{ |obj| block }] -> true or false
|
|
# enum.none?(pattern) -> true or false
|
|
#
|
|
# Passes each element of the collection to the given block. The method
|
|
# returns `true` if the block never returns `true`
|
|
# for all elements. If the block is not given, `none?` will return
|
|
# `true` only if none of the collection members is true.
|
|
#
|
|
# If a pattern is supplied instead, the method returns whether
|
|
# `pattern === element` for none of the collection members.
|
|
#
|
|
# %w(ant bear cat).none? { |word| word.length == 5 } #=> true
|
|
# %w(ant bear cat).none? { |word| word.length >= 4 } #=> false
|
|
# %w{ant bear cat}.none?(/d/) #=> true
|
|
# [1, 3.14, 42].none?(Float) #=> false
|
|
# [].none? #=> true
|
|
# [nil, false].none? #=> true
|
|
# [nil, true].none? #=> false
|
|
|
|
def none?(pat=NONE, &block)
|
|
if !NONE.equal?(pat)
|
|
self.each do |*val|
|
|
return false if pat === val.__svalue
|
|
end
|
|
elsif block
|
|
self.each do |*val|
|
|
return false if block.call(*val)
|
|
end
|
|
else
|
|
self.each do |*val|
|
|
return false if val.__svalue
|
|
end
|
|
end
|
|
true
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.one? [{ |obj| block }] -> true or false
|
|
# enum.one?(pattern) -> true or false
|
|
#
|
|
# Passes each element of the collection to the given block. The method
|
|
# returns `true` if the block returns `true`
|
|
# exactly once. If the block is not given, `one?` will return
|
|
# `true` only if exactly one of the collection members is
|
|
# true.
|
|
#
|
|
# If a pattern is supplied instead, the method returns whether
|
|
# `pattern === element` for exactly one collection member.
|
|
#
|
|
# %w(ant bear cat).one? { |word| word.length == 4 } #=> true
|
|
# %w(ant bear cat).one? { |word| word.length > 4 } #=> false
|
|
# %w(ant bear cat).one? { |word| word.length < 4 } #=> false
|
|
# %w{ant bear cat}.one?(/t/) #=> false
|
|
# [nil, true, 99].one? #=> false
|
|
# [nil, true, false].one? #=> true
|
|
# [ nil, true, 99 ].one?(Integer) #=> true
|
|
# [].one? #=> false
|
|
|
|
def one?(pat=NONE, &block)
|
|
count = 0
|
|
if !NONE.equal?(pat)
|
|
self.each do |*val|
|
|
count += 1 if pat === val.__svalue
|
|
return false if count > 1
|
|
end
|
|
elsif block
|
|
self.each do |*val|
|
|
count += 1 if block.call(*val)
|
|
return false if count > 1
|
|
end
|
|
else
|
|
self.each do |*val|
|
|
count += 1 if val.__svalue
|
|
return false if count > 1
|
|
end
|
|
end
|
|
|
|
count == 1 ? true : false
|
|
end
|
|
|
|
# ISO 15.3.2.2.1
|
|
# call-seq:
|
|
# enum.all? [{ |obj| block } ] -> true or false
|
|
# enum.all?(pattern) -> true or false
|
|
#
|
|
# Passes each element of the collection to the given block. The method
|
|
# returns `true` if the block never returns
|
|
# `false` or `nil`. If the block is not given,
|
|
# Ruby adds an implicit block of `{ |obj| obj }` which will
|
|
# cause #all? to return `true` when none of the collection members are
|
|
# `false` or `nil`.
|
|
#
|
|
# If a pattern is supplied instead, the method returns whether
|
|
# `pattern === element` for every collection member.
|
|
#
|
|
# %w[ant bear cat].all? { |word| word.length >= 3 } #=> true
|
|
# %w[ant bear cat].all? { |word| word.length >= 4 } #=> false
|
|
# %w[ant bear cat].all?(/t/) #=> false
|
|
# [1, 2i, 3.14].all?(Numeric) #=> true
|
|
# [nil, true, 99].all? #=> false
|
|
#
|
|
def all?(pat=NONE, &block)
|
|
if !NONE.equal?(pat)
|
|
self.each {|*val| return false unless pat === val.__svalue}
|
|
elsif block
|
|
self.each {|*val| return false unless block.call(*val)}
|
|
else
|
|
self.each {|*val| return false unless val.__svalue}
|
|
end
|
|
true
|
|
end
|
|
|
|
# ISO 15.3.2.2.2
|
|
# call-seq:
|
|
# enum.any? [{ |obj| block }] -> true or false
|
|
# enum.any?(pattern) -> true or false
|
|
#
|
|
# Passes each element of the collection to the given block. The method
|
|
# returns `true` if the block ever returns a value other
|
|
# than `false` or `nil`. If the block is not
|
|
# given, Ruby adds an implicit block of `{ |obj| obj }` that
|
|
# will cause #any? to return `true` if at least one of the collection
|
|
# members is not `false` or `nil`.
|
|
#
|
|
# If a pattern is supplied instead, the method returns whether
|
|
# `pattern === element` for any collection member.
|
|
#
|
|
# %w[ant bear cat].any? { |word| word.length >= 3 } #=> true
|
|
# %w[ant bear cat].any? { |word| word.length >= 4 } #=> true
|
|
# %w[ant bear cat].any?(/d/) #=> false
|
|
# [nil, true, 99].any?(Integer) #=> true
|
|
# [nil, true, 99].any? #=> true
|
|
# [].any? #=> false
|
|
#
|
|
def any?(pat=NONE, &block)
|
|
if !NONE.equal?(pat)
|
|
self.each {|*val| return true if pat === val.__svalue}
|
|
elsif block
|
|
self.each {|*val| return true if block.call(*val)}
|
|
else
|
|
self.each {|*val| return true if val.__svalue}
|
|
end
|
|
false
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj
|
|
# enum.each_with_object(obj) -> an_enumerator
|
|
#
|
|
# Iterates the given block for each element with an arbitrary
|
|
# object given, and returns the initially given object.
|
|
#
|
|
# If no block is given, returns an enumerator.
|
|
#
|
|
# (1..10).each_with_object([]) { |i, a| a << i*2 }
|
|
# #=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
|
|
#
|
|
|
|
def each_with_object(obj, &block)
|
|
return to_enum(:each_with_object, obj) unless block
|
|
|
|
self.each {|*val| block.call(val.__svalue, obj) }
|
|
obj
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.reverse_each { |item| block } -> enum
|
|
# enum.reverse_each -> an_enumerator
|
|
#
|
|
# Builds a temporary array and traverses that array in reverse order.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# (1..3).reverse_each { |v| p v }
|
|
#
|
|
# produces:
|
|
#
|
|
# 3
|
|
# 2
|
|
# 1
|
|
#
|
|
|
|
def reverse_each(&block)
|
|
return to_enum(:reverse_each) unless block
|
|
|
|
ary = self.to_a
|
|
i = ary.size - 1
|
|
while i>=0
|
|
block.call(ary[i])
|
|
i -= 1
|
|
end
|
|
self
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.cycle(n=nil) { |obj| block } -> nil
|
|
# enum.cycle(n=nil) -> an_enumerator
|
|
#
|
|
# Calls *block* for each element of *enum* repeatedly _n_
|
|
# times or forever if none or `nil` is given. If a non-positive
|
|
# number is given or the collection is empty, does nothing. Returns
|
|
# `nil` if the loop has finished without getting interrupted.
|
|
#
|
|
# Enumerable#cycle saves elements in an internal array so changes
|
|
# to *enum* after the first pass have no effect.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# a = ["a", "b", "c"]
|
|
# a.cycle { |x| puts x } # print, a, b, c, a, b, c,.. forever.
|
|
# a.cycle(2) { |x| puts x } # print, a, b, c, a, b, c.
|
|
#
|
|
|
|
def cycle(nv = nil, &block)
|
|
return to_enum(:cycle, nv) unless block
|
|
|
|
n = nil
|
|
|
|
if nv.nil?
|
|
n = -1
|
|
else
|
|
n = nv.__to_int
|
|
return nil if n <= 0
|
|
end
|
|
|
|
ary = []
|
|
each do |*i|
|
|
ary.push(i)
|
|
yield(*i)
|
|
end
|
|
return nil if ary.empty?
|
|
|
|
while n < 0 || 0 < (n -= 1)
|
|
ary.each do |i|
|
|
yield(*i)
|
|
end
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.find_index(value) -> int or nil
|
|
# enum.find_index { |obj| block } -> int or nil
|
|
# enum.find_index -> an_enumerator
|
|
#
|
|
# Compares each entry in *enum* with <em>value</em> or passes
|
|
# to <em>block</em>. Returns the index for the first for which the
|
|
# evaluated value is non-false. If no object matches, returns
|
|
# `nil`
|
|
#
|
|
# If neither block nor argument is given, an enumerator is returned instead.
|
|
#
|
|
# (1..10).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> nil
|
|
# (1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 34
|
|
# (1..100).find_index(50) #=> 49
|
|
#
|
|
|
|
def find_index(val=NONE, &block)
|
|
return to_enum(:find_index, val) if !block && NONE.equal?(val)
|
|
|
|
idx = 0
|
|
if block
|
|
self.each do |*e|
|
|
return idx if block.call(*e)
|
|
idx += 1
|
|
end
|
|
else
|
|
self.each do |*e|
|
|
return idx if e.__svalue == val
|
|
idx += 1
|
|
end
|
|
end
|
|
nil
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.zip(arg, ...) -> an_array_of_array
|
|
# enum.zip(arg, ...) { |arr| block } -> nil
|
|
#
|
|
# Takes one element from *enum* and merges corresponding
|
|
# elements from each *args*. This generates a sequence of
|
|
# <em>n</em>-element arrays, where <em>n</em> is one more than the
|
|
# count of arguments. The length of the resulting sequence will be
|
|
# `enum#size`. If the size of any argument is less than
|
|
# `enum#size`, `nil` values are supplied. If
|
|
# a block is given, it is invoked for each output array, otherwise
|
|
# an array of arrays is returned.
|
|
#
|
|
# a = [ 4, 5, 6 ]
|
|
# b = [ 7, 8, 9 ]
|
|
#
|
|
# a.zip(b) #=> [[4, 7], [5, 8], [6, 9]]
|
|
# [1, 2, 3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
|
|
# [1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
|
|
# a.zip([1, 2], [8]) #=> [[4, 1, 8], [5, 2, nil], [6, nil, nil]]
|
|
#
|
|
# c = []
|
|
# a.zip(b) { |x, y| c << x + y } #=> nil
|
|
# c #=> [11, 13, 15]
|
|
#
|
|
|
|
def zip(*arg, &block)
|
|
result = block ? nil : []
|
|
arg = arg.map do |a|
|
|
unless a.respond_to?(:to_a)
|
|
raise TypeError, "wrong argument type #{a.class} (must respond to :to_a)"
|
|
end
|
|
a.to_a
|
|
end
|
|
|
|
i = 0
|
|
self.each do |*val|
|
|
a = []
|
|
a.push(val.__svalue)
|
|
idx = 0
|
|
while idx < arg.size
|
|
a.push(arg[idx][i])
|
|
idx += 1
|
|
end
|
|
i += 1
|
|
if result.nil?
|
|
block.call(a)
|
|
else
|
|
result.push(a)
|
|
end
|
|
end
|
|
result
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.to_h -> hash
|
|
#
|
|
# Returns the result of interpreting *enum* as a list of
|
|
# `[key, value]` pairs.
|
|
#
|
|
# %i[hello world].each_with_index.to_h
|
|
# # => {:hello => 0, :world => 1}
|
|
#
|
|
|
|
def to_h(&blk)
|
|
h = {}
|
|
if blk
|
|
self.each do |v|
|
|
v = blk.call(v)
|
|
raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
|
|
raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
|
|
h[v[0]] = v[1]
|
|
end
|
|
else
|
|
self.each do |*v|
|
|
v = v.__svalue
|
|
raise TypeError, "wrong element type #{v.class} (expected Array)" unless v.is_a? Array
|
|
raise ArgumentError, "element has wrong array length (expected 2, was #{v.size})" if v.size != 2
|
|
h[v[0]] = v[1]
|
|
end
|
|
end
|
|
h
|
|
end
|
|
|
|
def uniq(&block)
|
|
hash = {}
|
|
if block
|
|
self.each do|*v|
|
|
v = v.__svalue
|
|
hash[block.call(v)] ||= v
|
|
end
|
|
else
|
|
self.each do|*v|
|
|
v = v.__svalue
|
|
hash[v] ||= v
|
|
end
|
|
end
|
|
hash.values
|
|
end
|
|
|
|
def filter_map(&blk)
|
|
return to_enum(:filter_map) unless blk
|
|
|
|
ary = []
|
|
self.each do |*x|
|
|
x = blk.call(*x)
|
|
ary.push x if x
|
|
end
|
|
ary
|
|
end
|
|
|
|
alias filter select
|
|
|
|
def grep_v(pattern, &block)
|
|
ary = []
|
|
self.each {|*val|
|
|
sv = val.__svalue
|
|
unless pattern === sv
|
|
ary.push((block)? block.call(*val): sv)
|
|
end
|
|
}
|
|
ary
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.tally -> a_hash
|
|
#
|
|
# Tallys the collection. Returns a hash where the keys are the
|
|
# elements and the values are numbers of elements in the collection
|
|
# that correspond to the key.
|
|
#
|
|
# ["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}
|
|
def tally
|
|
hash = {}
|
|
self.each do |*x|
|
|
x = x.__svalue
|
|
hash[x] = (hash[x]||0)+1
|
|
end
|
|
hash
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.sum(count=1) -> numeric
|
|
# enum.sum(count=1){...} -> numeric
|
|
#
|
|
# Returns the sum of elements. For example, [e1, e2, e3].sum
|
|
# returns e1 + e2 + e3. If a block is given, each element is
|
|
# processed by the block, e.g [e1, e2, e3].sum{_1.m} gives
|
|
# e1.m + e2.m + e3.m.
|
|
#
|
|
def sum(init=0,&block)
|
|
result=init
|
|
if block
|
|
self.each do |*e|
|
|
result += block.call(*e)
|
|
end
|
|
else
|
|
self.each do |*e|
|
|
result += e.__svalue
|
|
end
|
|
end
|
|
result
|
|
end
|
|
|
|
##
|
|
# call-seq:
|
|
# enum.each_entry { |obj| block } -> enum
|
|
# enum.each_entry -> an_enumerator
|
|
#
|
|
# Calls block once for each element in self, passing that
|
|
# element as a parameter, converting multiple values from yield to an
|
|
# array.
|
|
#
|
|
# If no block is given, an enumerator is returned instead.
|
|
#
|
|
# class Foo
|
|
# include Enumerable
|
|
# def each
|
|
# yield 1
|
|
# yield 1, 2
|
|
# yield
|
|
# end
|
|
# end
|
|
# Foo.new.each_entry{ |o| p o }
|
|
#
|
|
# produces:
|
|
#
|
|
# 1
|
|
# [1, 2]
|
|
# nil
|
|
#
|
|
def each_entry(*args, &blk)
|
|
return to_enum(:each_entry) unless blk
|
|
self.each do |*a|
|
|
yield a.__svalue
|
|
end
|
|
return self
|
|
end
|
|
end
|
|
|
|
class Array
|
|
def sort_by(&block)
|
|
return to_enum(:sort_by) unless block
|
|
|
|
ary = []
|
|
self.each_with_index {|e, i|
|
|
ary.push([block.call(e), i])
|
|
}
|
|
if ary.size > 1
|
|
ary.sort!
|
|
end
|
|
ary.collect! {|e,i| self[i]}
|
|
end
|
|
|
|
def sort_by!(&block)
|
|
self.replace(self.sort_by(&block))
|
|
end
|
|
end
|