Ruby Array Method Arrangement

Posted by ricoche on Tue, 07 May 2019 13:35:03 +0200

Array method collation

Method List:

  • all(), any(), none() and one() Testing whether all or part of the elements in an array satisfy a given condition. Conditions can be determined in a block of statements or parameters.
  • append() Equivalent to push()
  • bsearch() Dichotomy Finding Elements
  • bsearch_index() Dichotomy Finds Elements and Returns Index Location
  • count() Calculate the number of elements in an array that satisfy the conditions. length(), size() are equivalent to count() without parameters.
  • collect() and collect! () Equivalent to map
  • combination() Array elements, see also: permutation()
  • compact() and compact! () Remove all nil elements from the array
  • cycle() Loop iterates over the entire array many times
  • delete() Delete elements in an array that are higher than a certain value, and pay attention to the original modification
  • delete_at() Delete elements at an index position in an array, similar to slice!(), and pay attention to the original modification
  • delete_if() Remove elements that satisfy the conditions in the statement block directly from the array, and return the remaining elements as an array. Note: It's original modification.
  • dig() Level by level elements from nested arrays
  • drop() Remove n elements from front to back, and return the remaining elements as new arrays instead of modifying them in place
  • drop_while() Delete elements from front to back until you encounter the first element that does not satisfy the conditions in the block
  • fetch() Gets the element at a given index, but defines the processing logic when the index crosses the boundary
  • fill() Replacement and modification of elements within a given range
  • filter() and filter! () Equivalent to select(), select!()
  • first() Returns one or more elements of the array header
  • flatten() and flatten! () Flattening nested arrays hierarchically
  • hash The hash value of the array, eql? Method is used to compare objects with hash value.
  • include?() To determine whether an element exists in an array
  • index() and rindex() Search for the index position of an element in an array
  • initialize_copy() Replace the current array element with an element in another array
  • keep_if() Remove elements that do not satisfy the conditions in the statement block directly from the array, and return the remaining elements as an array. That is to say, the elements satisfying the conditions are retained. Note: It's original modification.
  • last() Returns one or more elements at the end of an array
  • length() Returns the number of array elements, length(), size() and count() with no parameters are equivalent
  • map() and map! () Iterate each element in the array and execute the logic in the statement block for each of them
  • permutation() To combine elements of an array, see also: combination()
  • pop() Remove one or more elements from the end of the array and return the removed elements
  • prepend() Equivalent to unshift()
  • product() Combining elements of multiple arrays
  • push() To append one or more elements to the end of an array and return the appended array, equivalent to append()
  • reject() and reject! () Select elements that do not meet the criteria in the array according to the rules in the statement block
  • repeated_combination() Look at the example.
  • repeated_permutation() Look at the example.
  • replace() Equivalent to initialize_copy()
  • reverse() and reverse! () Inversion array
  • reverse_each() Reverse iteration array
  • rotate() and rotate! () Rotate arrays
  • select() and select! () Filtering elements that satisfy conditions in an array based on rules in a block of statements, similar to grep() in Perl
  • simple() Select one or n random elements from an array
  • shift() Remove one or more elements from the array header and return the removed elements
  • shuffle() and shuffle! () Disrupt arrays
  • size() Returns the number of array elements, length(), size() and count() with no parameters are equivalent
  • sum() Adding elements of an array, not limited to numerical additions
  • [sort() and sort! ()]: Sort arrays
  • [sort_by()]:
  • take() Return n elements from front to back
  • take_while() Return elements from front to back until you meet the first element that does not satisfy the conditions in the block
  • transpose() For row-column conversion of multidimensional arrays, a special case similar to zip()
  • uniq() and uniq! () Remove duplicate elements from arrays
  • unshift() Insert one or more given elements into the array head and return the inserted array
  • zip() Merge elements of most groups

map() and map! ()

Iterate each element in the array, and execute the logic in the block for each of them, and return the new array.

map() does not modify the original array object, map! () modifies the original object.

map() and collect() are equivalent, the same as map! () and collect! () are equivalent.

arr = [1, 2, 3, 4, 5]
new_arr = arr.map{|a| 2*a}
p new_arr1    # [2, 4, 6, 8, 10]
p arr         # [1, 2, 3, 4, 5]

new_arr1 = arr.map!{|a| a**2}
p arr         # [1, 4, 9, 16, 25]
p new_arr1    # [1, 4, 9, 16, 25]

zip()

arr.zip(arg, ...) → new_ary
arr.zip(arg, ...) {|arr| block} → nil

Combine the elements of 0 or more arg arrays and arr arrays one by one. When merging, the number of elements in arr should be taken as the criterion, the insufficient elements should be supplemented by nil, and the redundant elements should be neglected.

a = [ 4, 5, 6 ]
b = [ 7, 8, 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]]

If you use statement blocks, then each merged subarray will be passed to the variables in the statement blocks, and then the logic of the statement blocks will be applied, but note that the result it returns is nil. Therefore, the blocks in the zip() block should be those statements that can actually be operated on, rather than returning the result of the operation as a return value, which will discard the result. Look at the following example:

a = [ 4, 5, 6 ]
b = [ 7, 8, 9 ]
[1, 2].zip(a, b)      # [[1, 4, 7], [2, 5, 8]]

[1, 2].zip(a, b) do |x|
  x.reduce(:+)         # (1). Irrational
end

[1, 2].zip(a, b) do |x|
  p x.reduce(:+)       # (2) reasonable.
end

sum = 0
[1, 2].zip(a, b) do |x|
  sum += x.reduce(:+)  # (3) reasonable.
end
p sum

First, the variables that zip() passed to the statement block twice above are [1, 4, 7] and [2, 5, 8]. x.reduce(:+) denotes the addition of all elements in an x container (here an array). Therefore, the result of the first iteration is 1 + 4 + 7 = 12, and the result of the second iteration is 2 + 5 + 8 = 15.

But in (1), it just adds, and after adding, the result is discarded. It will not be returned as an element of a new array, because zip() returns nil instead of a new array when using a statement block.

So, in (2), we add a p() action to the result after adding, which is the result of using x.reduce, and we don't discard it.

Similarly, in (3), the sum result is added to the sum so that the value of the last sum is retained. The result of x.reduce is also used here, and it is not discarded.


select() and select! ()

filter() and filter!() are equivalent to select() and select!(), respectively.

Iterate the array and select the elements that meet the test conditions in the statement block from the array, and finally form a new array.

select() does not modify the original array object, and select!() modifies the original object.

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.select {|a| a > 3}
p new_arr      # [4, 5, 6]
p arr          # [1, 2, 3, 4, 5, 6]

new_arr = arr.select! {|a| a > 3}
p new_arr      # [4, 5, 6]
p arr          # [4, 5, 6]

reject() and reject! ()

It is the opposite of select(), which filters elements from an array that do not meet the criteria.

reject() does not modify the original array object, reject!() modifies the original object.

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.reject {|a| a > 3}
p new_arr      # [1, 2, 3]
p arr          # [1, 2, 3, 4, 5, 6]

new_arr = arr.reject! {|a| a > 3}
p new_arr      # [1, 2, 3]
p arr          # [1, 2, 3]

keep_if()

keep_if {|item| block} → ary
keep_if → Enumerator

keep_if() deletes elements from the array that do not satisfy the conditions in the statement block, that is, retain elements that satisfy the conditions.

Pay attention to modifying objects in place.

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.keep_if {|a| a < 4}
p new_arr   # [1, 2, 3]
p arr       # [1, 2, 3]

uniq() and uniq! ()

ary.uniq                -> new_ary
ary.uniq {|item| ...}   -> new_ary
ary.uniq!                -> ary or nil
ary.uniq! {|item| ...}   -> ary or nil

For the syntax of block format, each element is iterated, and then the comparison of repetitive values is based on the return value in the block.

For uniq!(), if no duplicate element can be removed, it returns to nil, when the original array remains unchanged, which is a special case with a suffix! But does not change the original object. In other cases, these methods all return to the de-duplicated array.

a = [ "a", "a", "b", "b", "c" ]
a.uniq   # ["a", "b", "c"], a does not change

b = [["student","sam"], ["student","george"], ["teacher","matz"]]
b.uniq {|s| s.first}  # [["student","sam"],["teacher","matz"], b unchanged


a = [ "a", "a", "b", "b", "c" ]
a.uniq!   # ["a", "b", "c"], a has changed

b = [ "a", "b", "c" ]
b.uniq!   # nil, b remain unchanged

c = [["student","sam"], ["student","george"], ["teacher","matz"]]
c.uniq! {|s| s.first}  # [["student","sam"],["teacher","matz"], c has changed

compact() and compact! ()

compact! → new_ary
compact! → ary or nil

Remove all nil elements from the array.

The exclamation mark method indicates the original modification, and returns nil if no nil element can be removed.

["a",nil,"b",nil,"c",nil].compact #["a","b","c"]

["a",nil,"b",nil,"c"].compact! # ["a","b","c"]
["a","b","c"].compact!         # nil



all(), any(), none() and one()

all? [{ |obj| block } ] → true or false
all?(pattern) → true or false

any? [{ |obj| block } ] → true or false
any?(pattern) → true or false

none? [{ |obj| block } ] → true or false
none?(pattern) → true or false

one? [{ |obj| block } ] → true or false
one?(pattern) → true or false

For these methods, there are three kinds of behavior:

  • When a statement block is used, it is determined whether all, any, none, and one elements in the container satisfy the conditions in the statement block.
  • When a block of statements is not used but a given parameter is given, the test symbol === is used to determine whether all, any, none, and one elements in the container satisfy the conditions.
  • When a block of statements is not used and no parameters are given, it is determined whether all, any, none, and one elements in the container are true.

Special attention should be paid to empty arrays. Although empty arrays themselves are bool true, empty arrays have no elements:

  • For all(), an empty array means that all elements are true, because it has no elements at all, so it returns true.
  • For any(), an empty array indicates that no element is true, because it has no element at all, so it returns false.
  • For none(), an empty array indicates that no element is true, because it has no element at all, so it returns true.
  • For one(), an empty array does not have an element that is true, because it has no element at all, so it returns false.
# all()
%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
[].all?                                           # true
# any()
%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
# none()
%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].none?                                      # true
[nil, false].none?                               # true
[nil, false, true].none?                         # false
# one()
%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

count()

Calculate the number of elements that satisfy the conditions in the array.

count → int
count(obj) → int
count {|item| block} → int
  • Calculate the number of all elements in an array without parameters
  • When there are parameters, count the number of elements in the array that are equal to the obj object, and test the equivalence with ==.
  • When a statement block is executed, each element of the array is iterated and the number of elements that meet the statement block criteria is calculated.
ary = [1, 2, 4, 2]
ary.count                  # 4. Number of array elements
ary.count(2)               # 2, the number of elements equal to 2
ary.count {|x| x%2 == 0}   # 3. Number of even elements


length() and size()

Both are equivalent, returning the number of elements in the array. Equivalent to count() without parameters.

cycle()

cycle(n=nil) {|obj| block} → nil
cycle(n=nil) → Enumerator

Iterate each element of the array and call the statement block, and then loop through the entire array n times of iteration process (note that the number of times is calculated by the whole array, not for each element, so first iterate through the array, then iterate through the second array, and so on).

If the parameter or parameter is not given nil, the iteration is infinite.

a = ["a", "b", "c"]
a.cycle {|x| puts x}     # a,b,c,a,b,c, ... forever
a.cycle(2) {|x| puts x}  # a,b,c,a,b,c

delete()

ary.delete(obj)            -> item or nil
ary.delete(obj) {block}    -> item or result of block

Delete all objects equal to obj in the array and return the last deleted element. If no element can be deleted, it returns nil. If a statement block is used, the result of the statement block is returned without element deletion, instead of nil. It is equivalent to the statement block providing default values instead of nil return values.

Pay attention to the original revision.

a = [ "a", "b", "b", "b", "c" ]
a.delete("b")                   # "b"
a                               # ["a", "c"]
a.delete("z")                   # nil
a.delete("z") {"not found"}     # "not found"

delete_at()

delete_at(index) → obj or nil

Delete all objects equal to obj in the array and return the last deleted element. If no element can be deleted, it returns nil. If a statement block is used, the result of the statement block is returned without element deletion, instead of nil. It is equivalent to the statement block providing default values instead of nil return values.

Pay attention to the original revision.

a = ["ant", "bat", "cat", "dog"]
a.delete_at(2)    # "cat"
a                 # ["ant", "bat", "dog"]
a.delete_at(99)   # nil

delete_if()

delete_if {|item| block} → ary
delete_if → Enumerator

delete_if() deletes elements from the array that satisfy the conditions in the statement block.

Pay attention to the original revision.

arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.delete_if {|a| a < 4}
p new_arr   # [4, 5, 6]
p arr       # [4, 5, 6]

dig()

dig(idx, ...) → object

Extract elements from the array according to the given index idx. This is mainly used to extract elements from multi-level nested arrays, especially complex arrays.

a = [[1, [2, 3]]]

a.dig(0, 1, 1)                  # 3
a.dig(1, 2, 3)                  # nil
a.dig(0, 0, 0)                  # TypeError: Integer does not have #dig method
[42, {foo: :bar}].dig(1, :foo)  # :bar

Among them:

dig(0,1,1) means that the element of idx=0 is first taken from array a, i.e. [1,[2,3], then the element of idx=1, i.e. [2,3], and finally the element of idx=1, i.e., 3.

Di (1,2,3) crosses the boundary in the first extraction because [[1,[2,3]] has only one element.

Di (0, 0, 0) gets [1,[2, 3] for the first time and 1 for the second time, because 1 is no longer an array, so the third element fetch is wrong.


drop() and take()

drop(n) → new_ary
take(n) → new_ary

take() returns the first n elements from the array header.

drop() deletes the first n elements from the array header and returns the remaining elements as a new array.

The original array remains unchanged.

# drop()
a = ["a", "b", "c"]
a.drop(2)    # Return ["c"], a unchanged

# take()
a = [1, 2, 3, 4, 5, 0]
a.take(3)    # [1, 2, 3]


drop_while() and take_while()

drop_while {|obj| block} → new_ary
drop_while → Enumerator

take_while {|obj| block} → new_ary
take_while → Enumerator

take_while() iterates over elements from the array header until it encounters elements that do not satisfy the conditions in the block, and then returns all iterated elements that satisfy the conditions.

drop_while() iterates over elements from the array header until it meets elements that do not satisfy the conditions in the block. The remaining elements are then returned as a new array.

Note that this is not a change in place.

# drop_while()
arr = [1, 2, 3, 4, 5, 6]
new_arr = arr.drop_while {|a| a<4}
p new_arr   # [4, 5, 6]
p arr       # [1, 2, 3, 4, 5, 6]

# take_while()
a = [1, 2, 3, 4, 5, 0]
a.take_while {|i| i < 3}    #=> [1, 2]

fetch()

fetch(index) → obj
fetch(index, default) → obj
fetch(index) {|index| block} → obj

Get the elements in the array according to the given index. If index crosses the boundary, it is processed according to three different forms:

  • Direct error reporting when no second parameter is given and no statement block is used
  • When the second parameter is given, the second parameter value is returned as the default value when index crosses the bounds.
  • When using a block of statements, the contents of the block of statements are executed when index crosses the bounds, and the index is passed to the variable of the block of statements.
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"

fill()

# Original revision
fill(obj) → ary
fill(obj, start [, length]) → ary
fill(obj, range) → ary

fill {|index| block} → ary
fill(start [, length]) {|index| block} → ary
fill(range) {|index| block} → ary

The first three forms replace the values of elements within a given range in an array with obj values:

  • fill(obj): Replace all elements with obj
  • fill(obj, start [, len]): Replacement starts with start, with len elements in length, and replaces all the elements that follow without len
  • fill(obj, range): Replace the range element specified by range

In the latter three forms, the passing array is indexed to the statement block, and the elements in a given range are replaced by the calculation results of the statement block, while those outside the range are retained by the index value elements.

a = [ "a", "b", "c", "d" ]
a.fill("x")              # ["x", "x", "x", "x"]
a.fill("z", 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]


first() and last()

first → obj or nil
first(n) → new_ary

last → obj or nil
last(n) → new_ary

Take one or n elements at the head or tail of an array.

  • When no parameter is given, it represents an element with a header or tail, and the array returns nil in space-time.
  • Given a parameter, the number of n elements representing the beginning or the end of an array element can be returned when it is not enough, and the number of empty arrays can not be retrieved when the array is space-time, so the number of empty arrays is returned.
a = %w(a b c d)

a.first      # "a"
a.last       # "d"
a.first(2)   # ["a", "b"]
a.last(2)    # ["c", "d"]
a.first(10)  # ["a", "b", "c", "d"]
a.last(10)   # ["a", "b", "c", "d"]
[].first     # nil
[].first(2)  # []



pop(), push(), and append()

push(obj, ...) → ary
append(obj, ...) → ary

pop → obj or nil
pop(n) → new_ary

Pay attention to the original revision.

  • push(): Appends a given element or elements to the end of the array, because it returns the array itself, so chain appending is possible.
  • append(): equivalent to push()
  • pop(): Remove one or n elements from the end of the array (returned as an array at this time), and return nil if the array is empty. Equivalent to slice!(-n,n)
# push(),append()
a = [ "a", "b", "c" ]
a.push("d","e","f")     # %w[a b c d e f]
[1,2,3].push(4).push(5) # [1,2,3,4,5]
# pop()
a = [ "a", "b", "c", "d" ]
a.pop     # "d"
a.pop(2)  # ["b", "c"]
a         # ["a"]



shift(), unshift() and prepend()

unshift(obj, ...) → ary
prepend(obj, ...) → ary

shift → obj or nil
shift(n) → new_ary

Pay attention to the original revision.

  • unshift(): Inserting one or more elements into the head of an array causes the original elements of the entire array to move backwards.
  • prepend(): equivalent to unshift()
  • shift(): Removing and returning one or n elements from the array header (returned as an array at this time) will cause the whole array to move forward. If the array is empty, return nil. Equivalent to slice!(0,n)
# unshift,prepend()
a = [ "b", "c", "d" ]
a.unshift("a")   #=> ["a", "b", "c", "d"]
a.unshift(1, 2)  #=> [ 1, 2, "a", "b", "c", "d"]
# shift
args = ["-m", "-q", "filename"]
args.shift     # "-m"
args           # ["-q", "filename"]

args = [ "-m", "-q", "filename" ]
args.shift(2)  #=> ["-m", "-q"]
args           #=> ["filename"]

flatten() and flatten! ()

flatten → new_ary 
flatten(level) → new_ary

flatten! → ary or nil
flatten!(level) → ary or nil

Flattening a multi-level nested array, level can specify the maximum pressure to that layer. For methods with exclamation suffix, if the array can no longer be pressed or the number of layers is insufficient, return nil.

s = [ 1, 2, 3 ]           # [1,2,3]
t = [ 4, 5, 6, [7, 8] ]   # [4,5,6,[7,8]]
a = [ s, t, 9, 10 ]       # [[1,2,3],[4,5,6,[7,8]],9,10]
a.flatten                 # [1,2,3,4,5,6,7,8,9,10]
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten(1)              # [1, 2, 3, [4, 5]]

a = [ 1, 2, [3, [4, 5] ] ]
a.flatten!   #=> [1, 2, 3, 4, 5]
a.flatten!   #=> nil, it's flattened
a            #=> [1, 2, 3, 4, 5]
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten!(1) #=> [1, 2, 3, [4, 5]]
a.flatten!(1) #=> [1, 2, 3, 4, 5]
a.flatten!(1) #=> nil

hash()

Calculate the hash value of the array. When eql?() is compared, the basis for comparison is hash value.

[1, 2].hash    # 2027605168499122706
[1, 2.0].hash  # 3393919734812826294

include?()

include?(object) → true or false

Determine whether an element is included in an array. The judgment is based on the use of== comparison.

a = [ "a", "b", "c" ]
a.include?("b")       # true
a.include?("z")       # false
[1, 2.0].include?(2)  # true

index() and rindex()

index(obj) → int or nil
index {|item| block} → int or nil
index → Enumerator

rindex(obj) → int or nil
rindex {|item| block} → int or nil
rindex → Enumerator

Search for elements in the array that satisfy the criteria and return their index location, and if not, return nil.

# index(obj),rindex(obj)
# Returns the position of the first and last element in the array equal to obj
# Test with "==="
a = [ "a", "b", "c" ]
p a.index("b")              # 1
p a.index("z")              # nil
p a.index {|x| x == "b"}    # 1

# (r)index {|item| block}
# Returns the location of the first / last element that satisfies the condition in the statement block
a = [ "a", "b", "b", "b", "c" ]
p a.rindex("b")             # 3
p a.rindex("z")             # nil
p a.rindex {|x| x == "b"}   # 3


initialize_copy() and replace()

They are equivalent.

initialize_copy(other_ary) → ary

Use other_ary arrays to replace elements in the current array, and shrink and expand as needed.

Pay attention to the original revision.

a = %w(a b c d e)     # ["a", "b", "c", "d", "e"]
a.replace(%w[x y z])  # ["x", "y", "z"]
a                     # ["x", "y", "z"]

join()

join(separator=$,) → str

Connect the elements of the array through the connector and convert them into strings to return.

When sep is not given, the default is $, which is used as a connector. If $, which is nil (the default is nil), the default is to use empty characters to connect.

Nested arrays are connected recursively.

The connector must be a string type.

In fact, the process of join() is to convert all elements of an array into strings using to_s, and then to_str to strings for the connectors.

["a","b","c"].join        # "abc"
["a","b","c"].join("-")   # "a-b-c"
["a",[1,2,[:x,:y]], "b" ].join("-")   # "a-1-2-x-y-b"

# The value cannot be used as a connector because it does not define to_str
%w(perl shell ruby).join(1) # TypeError


max() and min()

max → obj
max {|a, b| block} → obj
max(n) → array
max(n) {|a, b| block} → array

min → obj
min {|a, b| block} → obj
min(n) → array
min(n) {|a, b| block} → array

A parametric, non-statement block representation that returns the largest/smallest element from an array. Comparable module allows comparisons only when all elements in an array are implemented, that is, comparisons between different elements of an array can be made using <=>.

In block form, each element is passed to the block and processed, and then returned by <=> comparison.

The parameterized form means returning the largest/smallest n elements in an array, that is, returning the first few objects.

ary = %w(albatross dog horse)
ary.max                                   # "horse"
ary.max {|a, b| a.length <=> b.length}    # "albatross"
ary.max {|a, b| b.length <=> a.length}    # "dog"

ary = %w[albatross dog horse]
ary.max(2)                                # ["horse", "dog"]
ary.max(2){|a, b| a.length <=> b.length}  # ["albatross","horse"]
ary = %w(albatross dog horse)
a = ary.max do |a, b|
  x=a.length
  y=b.length
  y <=> x
end


permutation() and combination()

permutation {|p| block} → ary
permutation → Enumerator
permutation(n) {|p| block} → ary
permutation(n) → Enumerator

combination(n) {|c| block} → ary
combination(n) → Enumerator

permutation() arranges the elements of an array and returns the arrays that have been arranged.

  • When the parameter n is specified, all n elements are arranged
  • When the parameter n is not specified, n defaults to the array length, i.e., all elements are arranged.

combination() combines n elements of an array.

Note that the order of arrangement and combination is not guaranteed.

On the difference between permutation and combination:

  • Arrangement: From n different elements, take r non-repetitive elements, arranged in order, called from n to take r non-repetitive arrangement
  • Combination: Take r elements from n different elements and form a subset without considering the order of their elements. It is called unrestricted sum of R elements from n elements.

See the following example to understand:

# permutation() for permutation
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
# combination() for combination operations
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

When a statement block is used, each arranged subarray is passed to the variable of the statement block.

a = [1, 2, 3, 4]
a.combination(3) {|x| p x << "z" }
## Output:
## [1, 2, 3, "z"]
## [1, 2, 4, "z"]
## [1, 3, 4, "z"]
## [2, 3, 4, "z"]


repeated_combination() and repeated_permutation()

repeated_combination(n) {|c| block} → ary
repeated_combination(n) → Enumerator

repeated_permutation(n) {|p| block} → ary
repeated_permutation(n) → Enumerator

Repeat n arrays themselves, and arrange and combine the n arrays. Look at the examples.

# repeated_combination()
a = [1, 2, 3]
a.repeated_combination(1).to_a  # [[1], [2], [3]]
a.repeated_combination(2).to_a  # [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]]
a.repeated_combination(3).to_a  # [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3],
                                #    [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]]
a.repeated_combination(4).to_a  # [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3],
                                #    [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3],
                                #    [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]]
a.repeated_combination(0).to_a  # [[]] # one combination of length 0
# repeated_permutation()
a = [1, 2]
a.repeated_permutation(1).to_a  # [[1], [2]]
a.repeated_permutation(2).to_a  # [[1,1],[1,2],[2,1],[2,2]]
a.repeated_permutation(3).to_a  # [[1,1,1],[1,1,2],[1,2,1],[1,2,2],
                                #    [2,1,1],[2,1,2],[2,2,1],[2,2,2]]
a.repeated_permutation(0).to_a  # [[]] # one permutation of length 0

product()

product(other_ary, ...) → new_ary
product(other_ary, ...) {|p| block} → ary

Combine the elements of the array and other_ary and return.

If a statement block is used, each combined subarray is passed to the statement block and returned to the array itself (that is, a.product() {}).

[1,2,3].product([4,5])     # [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
[1,2].product([1,2])       # [[1,1],[1,2],[2,1],[2,2]]
[1,2].product([3,4],[5,6]) # [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                           #    [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
[1,2].product()            # [[1],[2]]
[1,2].product([])          # []
# Use block form
a = [1,2,3]
sub_a = a.product([4,5]) {|x| p x}
p sub_a

## Output:
=begin
[1, 4]
[1, 5]
[2, 4]
[2, 5]
[3, 4]
[3, 5]
[1, 2, 3]
=end

reverse() and reverse! ()

reverse → new_ary
reverse! → ary

Inversion of array elements. An exclamation mark indicates a reversal of the original position.

# reverse()
["a","b","c"].reverse   # ["c","b", a"]
[1].reverse             # [1]

# reverse!()
a = ["a","b","c"]
a.reverse!       # ["c","b","a"]
a                # ["c","b","a"]

reverse_each()

reverse_each {|item| block} → ary
reverse_each → Enumerator

Similar to each(), but reverse iteration, which starts at the end of the array.

a = [ "a", "b", "c" ]
a.reverse_each {|x| print x," "} # Output c b a

rotate() and rotate! ()

rotate(count=1) → new_ary
rotate!(count=1) → ary

Rotate the array so that the element at count position is the first element of the new array. The exclamation mark indicates the original modification.

a = [ "a", "b", "c", "d" ]
a.rotate         # ["b", "c", "d", "a"]
a                # ["a", "b", "c", "d"]
a.rotate(2)      # ["c", "d", "a", "b"]
a.rotate(-3)     # ["b", "c", "d", "a"]

a = [ "a", "b", "c", "d" ]
a.rotate!        # ["b", "c", "d", "a"]
a                # ["b", "c", "d", "a"]
a.rotate!(2)     # ["d", "a", "b", "c"]
a.rotate!(-3)    # ["a", "b", "c", "d"]

simple()

sample → obj
sample(random: rng) → obj
sample(n) → new_ary
sample(n, random: rng) → new_ary

Random selection of one or n elements from an array. The way to select random elements is to use random indexes to select them. If multiple random elements are selected, the indexing position of random elements ensures uniqueness, but duplicate elements may still be selected because the array itself may contain duplicate elements.

The parameter rng represents the generator that specifies the index random number to be generated.

When it is an empty array, the first form returns nil, and the second form returns an empty array.

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a.sample         # 7
a.sample(4)      # [6, 4, 2, 5]
a.sample(random: Random.new(1))     # 6
a.sample(4, random: Random.new(1))  # [6, 10, 9, 2]

shuffle() and shuffle! ()

shuffle → new_ary
shuffle(random: rng) → new_ary

shuffle! → ary
shuffle!(random: rng) → ary

Disturb array elements and return. The exclamation mark suffix indicates the original modification.

The rng parameter specifies the dust generator that generates the random number.

# shuffle()
a = [ 1, 2, 3 ]           # [1, 2, 3]
a.shuffle                 # [2, 3, 1]
a                         # [1, 2, 3]

a.shuffle(random: Random.new(1))  # [1, 3, 2]

# shuffle!()
a = [ 1, 2, 3 ]           # [1, 2, 3]
a.shuffle!                # [2, 3, 1]
a                         # [2, 3, 1]

a.shuffle!(random: Random.new(1))  # [1, 3, 2]

transpos()

transpose → new_ary

If it is a multidimensional array, it returns a new array after row and column conversion. If the number of elements is inconsistent, the error is reported directly.

a = [[1,2], [3,4], [5,6]]
a.transpose   # [[1, 3, 5], [2, 4, 6]]

[[1,2,3],[3,4],[5,6]].transpose # IndexError

sum()

sum(init=0) → number
sum(init=0) {|e| expr } → number

Returns the sum of each element addition operation. For example [e1, e2, e3].sum returns init + e1 + e2 + e3.

If a statement block is used, the statement block is executed on each element before adding.

If the array is empty, the init parameter value is returned.

[].sum                             # 0
[].sum(0.0)                        # 0.0
[1, 2, 3].sum                      # 6
[3, 5.5].sum                       # 8.5
[2.5, 3.0].sum(0.0) {|e| e * e }   # 15.25
[Object.new].sum                   # TypeError

It is not limited to the ability to perform numerical addition operations, as long as the initial value type is explicitly specified by the init parameter:

["a", "b", "c"].sum("")            # "abc"
[[1], [[2]], [3]].sum([])          # [1, [2], 3]

However, join() and flatten() both run faster than those described above.

["a", "b", "c"].join               # "abc"
[[1], [[2]], [3]].flatten(1)       # [1, [2], 3]

sort() and sort! ()

sort → new_ary
sort {|a, b| block} → new_ary

sort! → ary
sort! {|a, b| block} → ary

Sort the array elements and return. The suffix with exclamation marks indicates the original modification.

When no statement block is used, the sorting is based on comparing the use of <=> for each element.

When a statement block is used, it is sorted according to the basis specified in the statement block.

When the two elements are equal in comparison, there will be no guarantee of who is ahead and who is behind.

# sort()
ary = [ "d", "a", "e", "c", "b" ]
ary.sort                     # ["a","b","c","d","e"]
ary.sort {|a, b| a <=> b}    # ["a","b","c","d","e"]
ary.sort {|a, b| b <=> a}    # ["e","d","c","b","a"]

# sort!()
ary = [ "d", "a", "e", "c", "b" ]
ary.sort!                     # ["a","b","c","d","e"]
ary.sort! {|a, b| a <=> b}    # ["a","b","c","d","e"]
ary.sort! {|a, b| b <=> a}    # ["e","d","c","b","a"]

sort_by() and sort_by!()

sort_by() is taken from Enumerable of mix-in. sort_by!() is realized by Array himself.

sort_by { |obj| block } → array
sort_by → an_enumerator

sort_by! {|obj| block} → ary
sort_by! → Enumerator

Sort by the rules in the block. Default ascending sort.

a = %w(perl shell php python java ruby)

a.sort_by {|a| a.length}
   #=> %w[php java ruby perl shell python]
(a.sort_by {|a| a[-1]}).reverse
   #=> %w[ruby php python perl shell java]

The first sort statement is to sort the elements in ascending order according to their length.

The second sort statement is to sort the elements in ascending order according to the last character, and then reverse the sort result.


bsearch() and bserach_index()

bsearch {|x| block } → elem
bsearch_index {|x| block } → int or nil

Both of them work in the same way and are used to find elements by dichotomy. The only difference is to return the results. The former returns container elements, while the latter returns the corresponding index.

The search process of dichotomy algorithm is brief. But it is necessary to explain the two methods here. Take only the usage of the bsearch() method as an example.

The first requirement is that arrays are sorted, or monotonous for statement blocks.

bsearch() generally has two uses: find-minimum and find-any.

Find-minimum (when looking for a single element) requires the statement block to return true/false. When true is returned, it continues to the left, and when false is returned, it continues to the right. The last true element is returned until there is no element, or nil is returned when there is no true at all.

Find-any (that is, when looking for range elements) requires statement blocks to return negative, positive, and zero. When the positive number is returned, it continues to the right, when the negative number is returned, it continues to the left, and when it returns to zero, it stops.

find-minimum Example 1: Unequal Value Judgment

a = [-1, 1, 2, 4, 5]

p a.bsearch {|x| x > 2}  # 4

In this statement, the statement block first takes the middle element from the array (if it is even, such as six elements, then the fourth element), where the value of the element is 2.

It is judged by x > 2 and returned to false, so the subarray [4, 5] is continued to the right. Then get the intermediate element 5, 5 is greater than 2 and return true. So continue to the left, get elements 4, 4 greater than 2 and return true. You can't go on to the left, so you return the last true element, 4.

What is the whole process when we compare it with values less than 2 (e.g. 0) and greater than 2 (e.g. 3)?

find-minimum Example 2: Equivalent Judgment

arr_in = [-1, 1, 2, 4, 5]

p arr_in.bsearch { |x| x == -1 }  # nil
p arr_in.bsearch { |x| x == 1 }   # nil
p arr_in.bsearch { |x| x == 2 }   # 2
p arr_in.bsearch { |x| x == 4 }   # nil
p arr_in.bsearch { |x| x == 5 }   # 5

Why do some elements in an array return values, while others return nil?

For comparison of x = 1 and x = 1 and x = 4. First, we take the intermediate element 2, and the comparison result is false. Then we get the subarray [4, 5] to the right, and take the intermediate element 5 from it. The result is false, and we continue to go to the right, but no element can go to the right, and there has been no true result before, so we return to nil.

Similarly for x = 2 comparison. First, we take the intermediate element 2, and the comparison result is true. Then we get the subarray [-1, 1], the intermediate element 1, and the comparison result is false. Then we go to the right, but there are no elements. So we return the last true, that is, element 2.

For the comparison of x== 5, we first take the intermediate element 2 and the comparison result is false. Then we get the sub-array [4, 5] from the right, and the intermediate element 5 from the right. The result is true, then we continue to the left, and we get the sub-array [4]. So the intermediate element 4 is false and continues to the right, but there is no element to the right, so we return the last true element, that is 5.

find-any Example 3: Expressions that return positive, negative, and zero

a = [-1, 1, 2, 4, 5]

a.bsearch {|x| -1 - x}  # -1
a.bsearch {|x| 1 - x}   # 1
a.bsearch {|x| 2 - x}   # 2
a.bsearch {|x| 4 - x}   # 4
a.bsearch {|x| 5 - x}   # 5

a.bsearch {|x| 3 - x}   # nil

For - 1 - X and 1 - x, first take the intermediate element 2, return the negative result, then continue to the left, get the subarray [- 1, 1], take the intermediate element 1, return 0 for 1 - x, then immediately stop and return, for - 1 - x return - 2 continue to get [- 1], take the intermediate element subtract and return 0, then immediately stop and return - 1.

For 2-x, first take the intermediate element 2, return the result 0, stop immediately and return 2.

For 4-x and 5-x, we first take the intermediate element 2 and return the result to a positive number. So we continue to get the sub-array [4, 5] to the right and the intermediate element 5. For 5-x, we stop and return immediately. For 4-x, we get the negative number, then we get the sub-array [4] to the left, and finally return to 0 and stop.

For 3 - x, it first returns 1 as a positive number, takes a subarray [4, 5] to the right, and returns a negative number again. Then it takes [4] to the left, which is still a negative number, but no element can continue to the left, so it returns nil.

find-any Example 4:<=> Symbol Comparison

When using the <=> symbol in bsearch(), the value to be compared must be placed on the left, because the order of elements on both sides of the operator <=> is important.

a = [-1, 1, 2, 4, 5]

# To compare values on the left and parameters on the right
a.bsearch {|x| -1 <=> x}  # -1
a.bsearch {|x| 1 <=> x}   # 1
a.bsearch {|x| 2 <=> x}   # 2
a.bsearch {|x| 4 <=> x}   # 4
a.bsearch {|x| 5 <=> x}   # 5

a.bsearch {|x| 3 <=> x}   # nil

# To compare values on the right and parameters on the left
a.bsearch {|x| x <=> -1}   # nil
a.bsearch {|x| x <=> 1}   # nil
a.bsearch {|x| x <=> 2}   # 2
a.bsearch {|x| x <=> 4}   # nil
a.bsearch {|x| x <=> 5}   # nil

Firstly, the situation that the values to be compared are put on the left and the parameters on the right is analyzed.

For - 1 <=> X and 1 <=> x, the intermediate element 2 is first selected, and the result of comparison is - 1. Then the sub-array [- 1, 1] is continued to the left, and the intermediate element 1 is continued. For the return result 0 compared with 1 <=> x, the element 1 is immediately stopped and returned. For - 1 <=> x comparison, the return result is - 1, and then proceeds to the left from the array [- 1]. The final return result of the comparison is 0, returning the - 1 element.

For 2<=> x, the first time you take the intermediate element 2, you get 0, stop and return immediately.

For 4 <=> X and 5 <=> x, the intermediate element 2 is taken first, and the result of comparison is 1. Then the sub-array [4, 5] is obtained to the right, and the intermediate element 5 is continued. For the return result 0 of comparison of 5 <=> x, the element 51 is stopped immediately and returned. For the return result of 4 <=> x comparison - 1, then continue to take from the array [4], the final return result of comparison is 0, returning four elements.

For 3<=> x, self-analysis.

Then analyze the situation that the values to be compared are placed on the right and the parameters are placed on the right.

For x <=> - 1 and X <=> 1, the intermediate element 2 is taken first, and the result of comparison is 1. Then the sub-array [4, 5] is obtained to the right, so that no further backward analysis is needed, because they are all larger than the value of the price to be compared, so the sub-array is always taken to the right and eventually returned to nil.

For x<=> 2, the first time you take the intermediate element 2, you get 0, stop and return immediately.

For x <=> 4 and X <=> 5, the intermediate element 2 is taken first, and the result of comparison is -1, so the sub-array [-1, 1] is continued to be obtained to the right, so that no further backward analysis is needed, because they are smaller than the value of the ratio to be used, so that the sub-array is taken to the left all the time, resulting in the return of nil.

Topics: Ruby shell PHP Python