487 lines
12 KiB
Markdown
Vendored
487 lines
12 KiB
Markdown
Vendored
# mruby-enum-ext
|
|
|
|
This mrbgem extends the `Enumerable` module in mruby with additional useful methods.
|
|
|
|
## Added Methods
|
|
|
|
Below is a list of methods added to the `Enumerable` module, along with a brief description and example for each.
|
|
|
|
---
|
|
|
|
### `drop(n)`
|
|
|
|
Drops the first `n` elements from an enumerable and returns the rest of the elements in an array.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
a = [1, 2, 3, 4, 5, 0]
|
|
a.drop(3) #=> [4, 5, 0]
|
|
```
|
|
|
|
---
|
|
|
|
### `drop_while { |obj| block }`
|
|
|
|
Drops elements up to, but not including, the first element for which the block returns `nil` or `false`. Returns an array containing the remaining elements. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
a = [1, 2, 3, 4, 5, 0]
|
|
a.drop_while {|i| i < 3 } #=> [3, 4, 5, 0]
|
|
```
|
|
|
|
---
|
|
|
|
### `take(n)`
|
|
|
|
Returns the first `n` elements from an enumerable as an array.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
a = [1, 2, 3, 4, 5, 0]
|
|
a.take(3) #=> [1, 2, 3]
|
|
```
|
|
|
|
---
|
|
|
|
### `take_while { |obj| block }`
|
|
|
|
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.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
a = [1, 2, 3, 4, 5, 0]
|
|
a.take_while {|i| i < 3 } #=> [1, 2]
|
|
```
|
|
|
|
---
|
|
|
|
### `each_cons(n) { |a| block }`
|
|
|
|
Iterates the given block for each array of consecutive `n` elements. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
(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]
|
|
```
|
|
|
|
---
|
|
|
|
### `each_slice(n) { |a| block }`
|
|
|
|
Iterates the given block for each slice of `n` elements. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
(1..10).each_slice(3) {|a| p a}
|
|
# outputs below
|
|
# [1, 2, 3]
|
|
# [4, 5, 6]
|
|
# [7, 8, 9]
|
|
# [10]
|
|
```
|
|
|
|
---
|
|
|
|
### `group_by { |obj| block }`
|
|
|
|
Groups the collection by the result of the block. Returns a hash where keys are the evaluated result from the block and values are arrays of elements corresponding to the key. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
(1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
|
|
```
|
|
|
|
---
|
|
|
|
### `sort_by { |obj| block }`
|
|
|
|
Sorts the enumerable using a set of keys generated by mapping the values in the enumerable through the given block. Returns an array. If no block is given, an enumerator is returned. (Note: `Array#sort_by` and `Array#sort_by!` are also implemented for optimized in-place sorting for arrays).
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
%w(apple pear fig).sort_by { |word| word.length }
|
|
#=> ["fig", "pear", "apple"]
|
|
```
|
|
|
|
_(Example adapted, original was for `Array#sort_by`)_
|
|
|
|
---
|
|
|
|
### `first` / `first(n)`
|
|
|
|
Returns the first element, or the first `n` elements, of the enumerable. If the enumerable is empty, `first` returns `nil`, and `first(n)` returns an empty array.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
a = [1, 2, 3, 4, 5]
|
|
a.first #=> 1
|
|
a.first(3) #=> [1, 2, 3]
|
|
[].first #=> nil
|
|
[].first(3) #=> []
|
|
```
|
|
|
|
---
|
|
|
|
### `count` / `count(item)` / `count { |obj| block }`
|
|
|
|
Returns the number of items in the enumerable.
|
|
|
|
- If an argument `item` is given, counts items equal to `item`.
|
|
- If a block is given, counts elements yielding a true value.
|
|
- If no argument or block is given, counts all items.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
[1, 2, 3, 2].count #=> 4
|
|
[1, 2, 3, 2].count(2) #=> 2
|
|
[1, 2, 3, 4].count { |x| x%2 == 0 } #=> 2
|
|
```
|
|
|
|
---
|
|
|
|
### `flat_map { |obj| block }` (alias: `collect_concat`)
|
|
|
|
Returns a new array with the concatenated results of running the block once for every element. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
[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]
|
|
```
|
|
|
|
---
|
|
|
|
### `max_by { |obj| block }`
|
|
|
|
Returns the object in the enumerable that gives the maximum value from the given block. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
%w[albatross dog horse].max_by {|x| x.length } #=> "albatross"
|
|
```
|
|
|
|
---
|
|
|
|
### `min_by { |obj| block }`
|
|
|
|
Returns the object in the enumerable that gives the minimum value from the given block. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
%w[albatross dog horse].min_by {|x| x.length } #=> "dog"
|
|
```
|
|
|
|
---
|
|
|
|
### `minmax` / `minmax { |a, b| block }`
|
|
|
|
Returns a two-element array containing the minimum and maximum values. The first form assumes objects implement `Comparable`; the second uses the block to return `a <=> b`.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
a = %w(albatross dog horse)
|
|
a.minmax #=> ["albatross", "horse"]
|
|
a.minmax { |a, b| a.length <=> b.length } #=> ["dog", "albatross"]
|
|
```
|
|
|
|
---
|
|
|
|
### `minmax_by { |obj| block }`
|
|
|
|
Returns a two-element array containing the objects that correspond to the minimum and maximum values from the given block. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
%w(albatross dog horse).minmax_by { |x| x.length } #=> ["dog", "albatross"]
|
|
```
|
|
|
|
---
|
|
|
|
### `none?` / `none? { |obj| block }` / `none?(pattern)`
|
|
|
|
- With a block: Returns `true` if the block never returns `true` for any element.
|
|
- With a pattern: Returns `true` if `pattern === element` is never true for any element.
|
|
- With no argument or block: Returns `true` if none of the collection members are truthy.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
%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
|
|
```
|
|
|
|
---
|
|
|
|
### `one?` / `one? { |obj| block }` / `one?(pattern)`
|
|
|
|
- With a block: Returns `true` if the block returns `true` exactly once.
|
|
- With a pattern: Returns `true` if `pattern === element` is true for exactly one element.
|
|
- With no argument or block: Returns `true` if exactly one of the collection members is truthy.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
%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?(/t/) #=> false # (Note: original example might be specific to mruby version, "ant" and "cat" contain "t")
|
|
[nil, true, false].one? #=> true
|
|
[nil, true, 99].one?(Integer) #=> true
|
|
```
|
|
|
|
---
|
|
|
|
### `all?` / `all? { |obj| block }` / `all?(pattern)`
|
|
|
|
- With a block: Returns `true` if the block never returns `false` or `nil` for any element.
|
|
- With a pattern: Returns `true` if `pattern === element` is true for every element.
|
|
- With no argument or block: Returns `true` if all collection members are truthy.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
%w[ant bear cat].all? { |word| word.length >= 3 } #=> true
|
|
%w[ant bear cat].all? { |word| word.length >= 4 } #=> false
|
|
[1, 2i, 3.14].all?(Numeric) #=> true
|
|
[nil, true, 99].all? #=> false
|
|
```
|
|
|
|
---
|
|
|
|
### `any?` / `any? { |obj| block }` / `any?(pattern)`
|
|
|
|
- With a block: Returns `true` if the block ever returns a truthy value for an element.
|
|
- With a pattern: Returns `true` if `pattern === element` is true for any element.
|
|
- With no argument or block: Returns `true` if at least one collection member is truthy.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
%w[ant bear cat].any? { |word| word.length >= 3 } #=> true
|
|
%w[ant bear cat].any?(/d/) #=> false
|
|
[nil, true, 99].any?(Integer) #=> true
|
|
[nil, true, 99].any? #=> true
|
|
[].any? #=> false
|
|
```
|
|
|
|
---
|
|
|
|
### `each_with_object(obj) { |(*args), memo_obj| ... }`
|
|
|
|
Iterates the given block for each element with an arbitrary object `obj` given, and returns the initially given `obj`. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
(1..10).each_with_object([]) { |i, a| a << i*2 }
|
|
#=> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
|
|
```
|
|
|
|
---
|
|
|
|
### `reverse_each { |item| block }`
|
|
|
|
Builds a temporary array and traverses that array in reverse order, executing the block for each item. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
(1..3).reverse_each { |v| p v }
|
|
# produces:
|
|
# 3
|
|
# 2
|
|
# 1
|
|
```
|
|
|
|
---
|
|
|
|
### `cycle(n=nil) { |obj| block }`
|
|
|
|
Calls the block for each element repeatedly `n` times, or forever if `n` is `nil`. If `n` is non-positive or the collection is empty, does nothing. Returns `nil` if the loop finishes. If no block is given, an enumerator is returned.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
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.
|
|
```
|
|
|
|
---
|
|
|
|
### `find_index(value)` / `find_index { |obj| block }`
|
|
|
|
Compares each entry with `value` or passes to `block`. Returns the index for the first non-false evaluation. If no object matches, returns `nil`. If no argument or block is given, an enumerator is returned.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
(1..100).find_index { |i| i % 5 == 0 and i % 7 == 0 } #=> 34
|
|
(1..100).find_index(50) #=> 49
|
|
```
|
|
|
|
---
|
|
|
|
### `zip(arg, ...) { |arr| block }`
|
|
|
|
Takes one element from the enumerable and merges corresponding elements from each `arg`. Generates a sequence of n-element arrays. The length will be `enum#size`. If any argument is shorter, `nil` values are supplied. If a block is given, it's invoked for each output array; otherwise, an array of arrays is returned.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
a = [ 4, 5, 6 ]
|
|
b = [ 7, 8, 9 ]
|
|
a.zip(b) #=> [[4, 7], [5, 8], [6, 9]]
|
|
[1, 2].zip(a, b) #=> [[1, 4, 7], [2, 5, 8]]
|
|
c = []
|
|
a.zip(b) { |x, y| c << x + y } #=> nil
|
|
c #=> [11, 13, 15]
|
|
```
|
|
|
|
---
|
|
|
|
### `to_h { |element| block }`
|
|
|
|
Returns a hash by interpreting the enumerable as a list of `[key, value]` pairs. If a block is given, it's used to transform elements before they are converted into pairs.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
%i[hello world].each_with_index.to_h
|
|
# => {:hello => 0, :world => 1}
|
|
|
|
# With a block (example assumes a suitable block)
|
|
# (0..3).to_h {|x| [x, x*x] } # => {0=>0, 1=>1, 2=>4, 3=>9} (Conceptual example)
|
|
```
|
|
|
|
_(The `to_h` method in the source is a bit complex with its block handling; the example is simplified.)_
|
|
|
|
---
|
|
|
|
### `uniq { |item| block }`
|
|
|
|
Returns a new array by removing duplicate values. If a block is given, it will use the return value of the block for uniqueness comparison.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
[1, 2, 2, 3, 1].uniq #=> [1, 2, 3]
|
|
["a", "B", "c", "b"].uniq { |s| s.downcase } #=> ["a", "B", "c"]
|
|
```
|
|
|
|
---
|
|
|
|
### `filter_map { |obj| block }`
|
|
|
|
Returns a new array containing the truthy results of running the block for every element. If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
[-2, -1, 0, 1, 2].filter_map { |x| x*2 if x > 0 } #=> [2, 4]
|
|
```
|
|
|
|
---
|
|
|
|
### `grep_v(pattern) { |obj| block }`
|
|
|
|
Returns an array of elements that do NOT match the `pattern`. If a block is given, the elements of the result are passed to the block and the block's results are returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
a = ["apple", "banana", "orange", "grape"]
|
|
a.grep_v(/an/) #=> ["apple", "orange", "grape"]
|
|
a.grep_v(/an/) { |s| s.upcase } #=> ["APPLE", "ORANGE", "GRAPE"]
|
|
```
|
|
|
|
---
|
|
|
|
### `tally`
|
|
|
|
Tallies the collection. Returns a hash where keys are elements and values are their counts.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}
|
|
```
|
|
|
|
---
|
|
|
|
### `sum(initial=0) { |obj| block }`
|
|
|
|
Returns the sum of elements. If a block is given, each element is processed by the block before addition. `initial` is the starting value for the sum.
|
|
|
|
_Examples:_
|
|
|
|
```ruby
|
|
[1, 2, 3].sum #=> 6
|
|
[1, 2, 3].sum(10) #=> 16
|
|
[1, 2, 3].sum { |x| x * 2 } #=> 12
|
|
({a:1, b:2, c:3}).sum {|k,v| v} #=> 6 (Example from Ruby docs, assuming similar behavior)
|
|
```
|
|
|
|
---
|
|
|
|
### `each_entry(*args) { |obj| block }`
|
|
|
|
Calls block once for each element, passing that element as a parameter (converting multiple values from yield to an array). If no block is given, an enumerator is returned.
|
|
|
|
_Example:_
|
|
|
|
```ruby
|
|
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
|
|
```
|
|
|
|
---
|
|
|
|
**Note on `Array#sort_by` and `Array#sort_by!`**
|
|
|
|
The gem also provides optimized `sort_by` and `sort_by!` methods directly on the `Array` class. `sort_by!` sorts the array in place.
|
|
|
|
```ruby
|
|
arr = ["apple", "pear", "fig"]
|
|
arr.sort_by! { |word| word.length }
|
|
p arr #=> ["fig", "pear", "apple"]
|
|
```
|