class Array ## # call-seq: # ary.uniq! -> ary or nil # ary.uniq! { |item| ... } -> ary or nil # # Removes duplicate elements from `self`. # Returns `nil` if no changes are made (that is, no # duplicates are found). # # a = [ "a", "a", "b", "b", "c" ] # a.uniq! #=> ["a", "b", "c"] # b = [ "a", "b", "c" ] # b.uniq! #=> nil # c = [["student","sam"], ["student","george"], ["teacher","matz"]] # c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] # def uniq!(&block) if block hash = {} result = [] self.each do |val| key = block.call(val) unless hash.key?(key) hash[key] = true result << val end end if result.size == self.size nil else self.replace(result) end else __uniq! end end ## # call-seq: # ary.uniq -> new_ary # ary.uniq { |item| ... } -> new_ary # # Returns a new array by removing duplicate values in `self`. # # a = [ "a", "a", "b", "b", "c" ] # a.uniq #=> ["a", "b", "c"] # # b = [["student","sam"], ["student","george"], ["teacher","matz"]] # b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] # def uniq(&block) if block ary = self.dup ary.uniq!(&block) ary else __uniq end end # for efficiency def reverse_each(&block) return to_enum(:reverse_each) unless block i = self.size - 1 while i>=0 block.call(self[i]) i -= 1 end self end ## # call-seq: # ary.fetch(index) -> obj # ary.fetch(index, default) -> obj # ary.fetch(index) { |index| block } -> obj # # Tries to return the element at position `index`, but throws an IndexError # exception if the referenced `index` lies outside of the array bounds. This # error can be prevented by supplying a second argument, which will act as a # `default` value. # # Alternatively, if a block is given it will only be executed when an # invalid `index` is referenced. # # Negative values of `index` count from the end of the array. # # a = [ 11, 22, 33, 44 ] # a.fetch(1) #=> 22 # a.fetch(-1) #=> 44 # a.fetch(4, 'cat') #=> "cat" # a.fetch(100) { |i| puts "#{i} is out of bounds" } # #=> "100 is out of bounds" # def fetch(n, ifnone=NONE, &block) #warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block if block # Block case: use shared index helper + Ruby block handling normalized_index = __normalize_index(n) if normalized_index self[normalized_index] else block.call(n) end else # Fast C implementation for non-block cases __fetch(n, ifnone, NONE) end end ## # call-seq: # ary.fill(obj) -> ary # ary.fill(obj, start [, length]) -> ary # ary.fill(obj, range ) -> ary # ary.fill { |index| block } -> ary # ary.fill(start [, length] ) { |index| block } -> ary # ary.fill(range) { |index| block } -> ary # # The first three forms set the selected elements of `self` (which # may be the entire array) to `obj`. # # A `start` of `nil` is equivalent to zero. # # A `length` of `nil` is equivalent to the length of the array. # # The last three forms fill the array with the value of the given block, # which is passed the absolute index of each element to be filled. # # Negative values of `start` count from the end of the array, where +-1+ is # the last element. # # a = [ "a", "b", "c", "d" ] # a.fill("x") #=> ["x", "x", "x", "x"] # a.fill("w", -1) #=> ["x", "x", "x", "w"] # a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] # a.fill("y", 0..1) #=> ["y", "y", "z", "z"] # a.fill { |i| i*i } #=> [0, 1, 4, 9] # a.fill(-2) { |i| i*i*i } #=> [0, 1, 8, 27] # a.fill(1, 2) { |i| i+1 } #=> [0, 2, 3, 27] # a.fill(0..1) { |i| i+1 } #=> [1, 2, 3, 27] # def fill(arg0=nil, arg1=nil, arg2=nil, &block) if arg0.nil? && arg1.nil? && arg2.nil? && !block raise ArgumentError, "wrong number of arguments (given 0, expected 1..3)" end # Use shared C argument parser for all cases start, length = __fill_parse_arg(arg0, arg1, arg2, &block) if block # Block-based filling in Ruby i = start while i < start + length self[i] = block.call(i) i += 1 end else # Use fast C implementation for value filling __fill_exec(start, length, arg0) end self end ## # call-seq: # ary.delete_if { |item| block } -> ary # ary.delete_if -> Enumerator # # Deletes every element of `self` for which block evaluates to `true`. # # The array is changed instantly every time the block is called, not after # the iteration is over. # # See also Array#reject! # # If no block is given, an Enumerator is returned instead. # # scores = [ 97, 42, 75 ] # scores.delete_if {|score| score < 80 } #=> [97] def delete_if(&block) return to_enum(:delete_if) unless block result = [] idx = 0 len = size while idx < len elem = self[idx] result << elem unless block.call(elem) idx += 1 end self.replace(result) end ## # call-seq: # ary.reject! { |item| block } -> ary or nil # ary.reject! -> Enumerator # # Equivalent to Array#delete_if, deleting elements from `self` for which the # block evaluates to `true`, but returns `nil` if no changes were made. # # The array is changed instantly every time the block is called, not after # the iteration is over. # # See also Enumerable#reject and Array#delete_if. # # If no block is given, an Enumerator is returned instead. def reject!(&block) return to_enum(:reject!) unless block result = [] idx = 0 len = size while idx < len elem = self[idx] result << elem unless block.call(elem) idx += 1 end return nil if len == result.size self.replace(result) end ## # call-seq: # ary.bsearch {|x| block } -> elem # # By using binary search, finds a value from this array which meets # the given condition in O(log n) where n is the size of the array. # # You can use this method in two use cases: a find-minimum mode and # a find-any mode. In either case, the elements of the array must be # monotone (or sorted) with respect to the block. # # In find-minimum mode (this is a good choice for typical use case), # the block must return true or false, and there must be an index i # (0 <= i <= ary.size) so that: # # - the block returns false for any element whose index is less than # i, and # - the block returns true for any element whose index is greater # than or equal to i. # # This method returns the i-th element. If i is equal to ary.size, # it returns nil. # # ary = [0, 4, 7, 10, 12] # ary.bsearch {|x| x >= 4 } #=> 4 # ary.bsearch {|x| x >= 6 } #=> 7 # ary.bsearch {|x| x >= -1 } #=> 0 # ary.bsearch {|x| x >= 100 } #=> nil # # In find-any mode (this behaves like libc's bsearch(3)), the block # must return a number, and there must be two indices i and j # (0 <= i <= j <= ary.size) so that: # # - the block returns a positive number for ary[k] if 0 <= k < i, # - the block returns zero for ary[k] if i <= k < j, and # - the block returns a negative number for ary[k] if # j <= k < ary.size. # # Under this condition, this method returns any element whose index # is within i...j. If i is equal to j (i.e., there is no element # that satisfies the block), this method returns nil. # # ary = [0, 4, 7, 10, 12] # # try to find v such that 4 <= v < 8 # ary.bsearch {|x| 1 - (x / 4).truncate } #=> 4 or 7 # # try to find v such that 8 <= v < 10 # ary.bsearch {|x| 4 - (x / 2).truncate } #=> nil # # You must not mix the two modes at a time; the block must always # return either true/false, or always return a number. It is # undefined which value is actually picked up at each iteration. def bsearch(&block) return to_enum(:bsearch) unless block if idx = bsearch_index(&block) self[idx] else nil end end ## # call-seq: # ary.bsearch_index {|x| block } -> int or nil # # By using binary search, finds an index of a value from this array which # meets the given condition in O(log n) where n is the size of the array. # # It supports two modes, depending on the nature of the block and they are # exactly the same as in the case of #bsearch method with the only difference # being that this method returns the index of the element instead of the # element itself. For more details consult the documentation for #bsearch. def bsearch_index(&block) return to_enum(:bsearch_index) unless block low = 0 high = size satisfied = false while low < high mid = ((low+high)/2).truncate res = block.call(self[mid]) case res when 0 # find-any mode: Found! return mid when Numeric # find-any mode: Continue... in_lower_half = res < 0 when true # find-min mode in_lower_half = true satisfied = true when false, nil # find-min mode in_lower_half = false else raise TypeError, 'invalid block result (must be numeric, true, false or nil)' end if in_lower_half high = mid else low = mid + 1 end end satisfied ? low : nil end ## # call-seq: # ary.keep_if { |item| block } -> ary # ary.keep_if -> Enumerator # # Deletes every element of `self` for which the given block evaluates to # `false`. # # See also Array#select! # # If no block is given, an Enumerator is returned instead. # # a = [1, 2, 3, 4, 5] # a.keep_if { |val| val > 3 } #=> [4, 5] def keep_if(&block) return to_enum(:keep_if) unless block result = [] idx = 0 len = size while idx < len elem = self[idx] result << elem if block.call(elem) idx += 1 end self.replace(result) end ## # call-seq: # ary.select! {|item| block } -> ary or nil # ary.select! -> Enumerator # # Invokes the given block passing in successive elements from `self`, # deleting elements for which the block returns a `false` value. # # If changes were made, it will return `self`, otherwise it returns `nil`. # # See also Array#keep_if # # If no block is given, an Enumerator is returned instead. def select!(&block) return to_enum(:select!) unless block result = [] idx = 0 len = size while idx < len elem = self[idx] result << elem if block.call(elem) idx += 1 end return nil if len == result.size self.replace(result) end ## # call-seq: # ary.dig(idx, ...) -> object # # Extracts the nested value specified by the sequence of *idx* # objects by calling `dig` at each step, returning `nil` if any # intermediate step is `nil`. # def dig(idx,*args) idx = idx.__to_int n = self[idx] if args.size > 0 n&.dig(*args) else n end end ## # call-seq: # ary.permutation { |p| block } -> ary # ary.permutation -> Enumerator # ary.permutation(n) { |p| block } -> ary # ary.permutation(n) -> Enumerator # # When invoked with a block, yield all permutations of length `n` of the # elements of the array, then return the array itself. # # If `n` is not specified, yield all permutations of all elements. # # The implementation makes no guarantees about the order in which the # permutations are yielded. # # If no block is given, an Enumerator is returned instead. # # Examples: # # a = [1, 2, 3] # a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] # a.permutation(1).to_a #=> [[1],[2],[3]] # a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] # a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] # a.permutation(0).to_a #=> [[]] # one permutation of length 0 # a.permutation(4).to_a #=> [] # no permutations of length 4 def permutation(n=self.size, &block) n = n.__to_int return to_enum(:permutation, n) unless block size = self.size if n == 0 yield [] elsif 0 < n && n <= size i = 0 while i 0 ary = self[0...i] + self[i+1..-1] ary.permutation(n-1) do |c| yield result + c end else yield result end i += 1 end end self end ## # call-seq: # ary.combination(n) { |c| block } -> ary # ary.combination(n) -> Enumerator # # When invoked with a block, yields all combinations of length `n` of elements # from the array and then returns the array itself. # # The implementation makes no guarantees about the order in which the # combinations are yielded. # # If no block is given, an Enumerator is returned instead. # # Examples: # # a = [1, 2, 3, 4] # a.combination(1).to_a #=> [[1],[2],[3],[4]] # a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] # a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] # a.combination(4).to_a #=> [[1,2,3,4]] # a.combination(0).to_a #=> [[]] # one combination of length 0 # a.combination(5).to_a #=> [] # no combinations of length 5 def combination(n, &block) n = n.__to_int return to_enum(:combination, n) unless block size = self.size if n == 0 yield [] elsif n == 1 i = 0 while i new_ary # # Assumes that self is an array of arrays and transposes the rows and columns. # # If the length of the subarrays don't match, an IndexError is raised. # # Examples: # # a = [[1,2], [3,4], [5,6]] # a.transpose #=> [[1, 3, 5], [2, 4, 6]] def transpose return [] if empty? column_count = nil self.each do |row| raise TypeError unless row.is_a?(Array) column_count ||= row.size raise IndexError, 'element size differs' unless column_count == row.size end Array.new(column_count) do |column_index| self.map {|row| row[column_index] } end end ## # call-seq: # ary.to_h -> Hash # ary.to_h{|item| ... } -> Hash # # Returns the result of interpreting *array* as an array of # `[key, value]` pairs. If a block is given, it should # return `[key, value]` pairs to construct a hash. # # [[:foo, :bar], [1, 2]].to_h # # => {:foo => :bar, 1 => 2} # [1, 2].to_h{|x| [x, x*2]} # # => {1 => 2, 2 => 4} # def to_h(&blk) h = {} self.each do |v| v = blk.call(v) if blk raise TypeError, "wrong element type #{v.class}" unless Array === v raise ArgumentError, "wrong array length (expected 2, was #{v.length})" unless v.length == 2 h[v[0]] = v[1] end h end alias append push alias prepend unshift alias filter! select! ## # call-seq: # ary.fetch_values(idx, ...) -> array # ary.fetch_values(idx, ...) { |i| block } -> array # # Returns an array containing the values associated with the given indexes. # but also raises `IndexError` when one of indexes can't be found. # Also see `Array#values_at` and `Array#fetch`. # # a = ["cat", "dog", "cow"] # # a.fetch_values(2, 0) #=> ["cow", "cat"] # a.fetch_values(2, 5) # raises KeyError # a.fetch_values(2, 5) {|i| "BIRD" } #=> ["cow", "BIRD"] # def fetch_values(*idx, &block) if block idx.map do |i| self.fetch(i, &block) end else # Fast path: use C implementation for non-block cases idx.map do |i| __fetch(i, NONE, NONE) end end end ## # call-seq: # ary.product(*arys) -> array # ary.product(*arys) { |item| ... } -> self def product(*arys, &block) gen = __product_generate(arys, &block) return gen unless block if gen while group = __product_next(arys, gen) yield group end end self end ## # call-seq: # ary.repeated_combination(n) { |combination| ... } -> ary # ary.repeated_combination(n) -> Enumerator # # When invoked with a block, yields all length `n` combinations of elements # from the array, with replacement, and then returns the array itself. # # This means that, unlike `combination`, elements can be chosen more than once. # # The implementation makes no guarantees about the order in which the # combinations are yielded. # # If no block is given, an Enumerator is returned instead. # # Examples: # # a = [1, 2, 3] # a.repeated_combination(2).to_a #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]] def repeated_combination(n, &block) raise TypeError, "no implicit conversion into Integer" unless 0 <=> n return to_enum(:repeated_combination, n) unless block __repeated_combination(n, false, &block) end ## # call-seq: # ary.repeated_permutation(n) { |permutation| ... } -> ary # ary.repeated_permutation(n) -> Enumerator # # When invoked with a block, yields all length `n` permutations of elements # from the array, with replacement, and then returns the array itself. # # This means that, unlike `permutation`, elements can be chosen more than once. # # The implementation makes no guarantees about the order in which the # permutations are yielded. # # If no block is given, an Enumerator is returned instead. # # Examples: # # a = [1, 2] # a.repeated_permutation(2).to_a #=> [[1,1],[1,2],[2,1],[2,2]] def repeated_permutation(n, &block) n = n.__to_int raise TypeError, "no implicit conversion into Integer" unless 0 <=> n return to_enum(:repeated_permutation, n) unless block __repeated_combination(n, true, &block) end def __repeated_combination(n, permutation, &block) n = n.__to_int case n when 0 yield [] when 1 # Keep fast Ruby path for n=1 i = 0 while i < self.size yield [self[i]] i += 1 end else if n > 0 # Use C iterator for complex cases state = __combination_init(n, permutation) while (indices = __combination_next(state)) # Convert indices to elements in Ruby tmp = [nil] * n i = 0 while i < n tmp[i] = self[indices[i]] i += 1 end yield tmp end end end self end ## # call-seq: # ary.find(ifnone = nil) { |elem| block } -> obj or nil # ary.find(ifnone = nil) -> Enumerator # # Returns the first element for which the block returns a true value. # If no element matches and +ifnone+ is given, calls +ifnone+ and # returns its result. Otherwise returns +nil+. # # This is an optimized version of Enumerable#find for arrays. # # [1, 2, 3, 4].find { |x| x > 2 } #=> 3 # [1, 2, 3, 4].find { |x| x > 10 } #=> nil # [1, 2, 3, 4].find(->{0}) { |x| x > 10 } #=> 0 # def find(ifnone=nil, &block) return to_enum(:find, ifnone) unless block idx = 0 len = self.size while idx < len elem = self[idx] return elem if block.call(elem) idx += 1 end ifnone&.call end ## # call-seq: # ary.rfind(ifnone = nil) { |elem| block } -> obj or nil # ary.rfind(ifnone = nil) -> Enumerator # # Returns the last element for which the block returns a true value. # Searches from the end of the array to the beginning. # If no element matches and +ifnone+ is given, calls +ifnone+ and # returns its result. Otherwise returns +nil+. # # [1, 2, 3, 4, 3].rfind { |x| x == 3 } #=> 3 (the last one) # [1, 2, 3, 4].rfind { |x| x > 2 } #=> 4 # [1, 2, 3, 4].rfind { |x| x > 10 } #=> nil # [1, 2, 3, 4].rfind(->{0}) { |x| x > 10 } #=> 0 # def rfind(ifnone=nil, &block) return to_enum(:rfind, ifnone) unless block idx = self.size - 1 while idx >= 0 elem = self[idx] return elem if block.call(elem) idx -= 1 end ifnone&.call end end