Compare two consecutive elements in an array - ruby

I want to create a "bubble sort" method, which means that I take two consecutive elements in an array, compare them and if the left element is greater than the right element, they should switch the position. I want to repeat it until my array is sorted in ascending order.
My code only works partially. If my array is too big nothing will happen (I have to quit ruby with CTRL + C). With arrays smaller than 5 elements my code works fine:
def bubbles(array)
while array.each_cons(2).any? { |a, b| (a <=> b) >= 0 }
# "true" if there are two consecutives elements where the first one
# is greater than the second one. I know the error must be here somehow.
array.each_with_index.map do | number, index |
if array[index + 1].nil?
number
break
elsif number > array[index + 1]
array[index], array[index + 1] = array[index + 1], array[index] # Swap position!
else
number
end
end
end
p array
end
If I call my method with an array with 4 elements, it works fine:
bubbles([1, 5, 8, 3]) # => [1, 3, 5, 8]
If I call it with a bigger array, it doesn't work:
bubbles([5, 12, 2, 512, 999, 1, 2, 323, 2, 12]) # => Nothing happens. I have to quit ruby with ctrl + c.
Have I somehow created an infinite loop with my while statement?

The problem is in your stop condition. You won't stop until you have an array where each element is lesser than the next. But in your long array you have duplicated elements, so the sorted elements will have adjacent elements that are equal to each other.
Not being too fancy with your code will make your life easier :)
while array.each_cons(2).any? { |a, b| a > b }

I suggest you determine if the array is ordered in a separate method (and don't print the array from within the method:
def bubbles(array)
until ordered?(array)
...
end
array
end
Here's one way (among many) to define ordered?:
def ordered?(array)
enum = array.to_enum
loop do
return false if enum.next > enum.peek
end
true
end
ordered? [1,2,3,4,5] #=> true
ordered? [1,2,4,3,4] #=> false
Also, your code mutates the argument it receives (array), which is probably undesirable. You can avoid that by working on a copy, array.dup.

Related

Ruby code to iterate over every n-th element of an array and print it until all elements are printed?

I am asked to write some code in Ruby that iterates over every n-th element of an array and prints it until all elements of the array are printed.
The question reads:
Imagine an iterator that accesses an array in strides and runs some code at each stride. If the strides reach the end of the array then they simply begin anew from the array's beginning.
For example:
x = [0,1,2,3,4]
x.stride(1) do |elem|; puts elem; end # prints 0,1,2,3,4
x.stride(2) do |elem|; puts elem; end # prints 0,2,4,1,3
x.stride(8) do |elem|; puts elem; end # prints 0,3,1,4,2
[].stride(2) do |elem|; puts elem; end # does not print anything, but the code is correct
Assume that the stride is equal or greater than 1, and that both the stride and the array's size are not a integral/whole multiple of each other, meaning that the whole array can be printed using a given stride. Fill in the code that's missing:
class Array
def stride(step)
numelems = ... # size of the array
...
end
end
It is obvious that numelemns = self.length(). However am having trouble with the rest.
I am going to try writing some code in Python that accomplishes this task, but I am afraid that I will not be able to translate it to Ruby.
Any ideas? The answer should not be more than 4-5 lines long as the question is one that our proffessor gave us to solve in a couple of minutes.
A solution to this is provided below (thanks #user3574603):
class Array
def stride(step)
yield self[0]
(self * step).map.with_index do |element, index|
next element if index == 0
yield element if index % step == 0
end
end
end
The following assumes that arr.size and n are not both even numbers and arr.size is not a multiple of n.
def striding(arr, n)
sz = arr.size
result = '_' * sz
idx = 0
sz.times do
result[idx] = arr[idx].to_s
puts "S".rjust(idx+1)
puts result
idx = (idx + n) % sz
end
end
striding [1,2,3,4,5,6,7,8,9,1,2,3,4,5,6], 7
S
1______________
S
1______8_______
S
1______8______6
S
1_____78______6
S
1_____78_____56
S
1____678_____56
S
1____678____456
S
1___5678____456
S
1___5678___3456
S
1__45678___3456
S
1__45678__23456
S
1_345678__23456
S
1_345678_123456
S
12345678_123456
S
123456789123456
Here is an example where arr.size is a multiple of n.
striding [1,2,3,4,5,6], 3
S
1_____
S
1__4__
S
1__4__
S
1__4__
S
1__4__
S
1__4__
Here is an example where arr.size and n are both even numbers.
striding [1,2,3,4,5,6,7,8], 6
S
1_______
S
1_____7_
S
1___5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
S
1_3_5_7_
Imagine an iterator that accesses an array in strides and runs some code at each stride. If the strides reach the end of the array then they simply begin anew from the array's beginning.
Based on this specification, stride will always iterate forever, unless the array is empty. But that is not a problem, since we can easily take only the amount of elements we need.
In fact, that is a good design: producing an infinite stream of values lets the consumer decide how many they need.
A simple solution could look like this:
module CoreExtensions
module EnumerableExtensions
module EnumerableWithStride
def stride(step = 1)
return enum_for(__callee__, step) unless block_given?
enum = cycle
loop do
yield(enum.next)
(step - 1).times { enum.next }
end
self
end
end
end
end
Enumerable.include(CoreExtensions::EnumerableExtensions::EnumerableWithStride)
A couple of things to note here:
I chose to add the stride method to Enumerable instead of Array. Enumerable is Ruby's work horse for iteration and there is nothing in the stride method that requires self to be an Array. Enumerable is simply the better place for it.
Instead of directly monkey-patching Enumerable, I put the method in a separate module. That makes it easier to debug code for others. If they see a stride method they don't recognize, and inspect the inheritance chain of the object, they will immediately see a module named EnumerableWithStride in the inheritance chain and can make the reasonable assumption that the method is probably coming from here:
[].stride
# Huh, what is this `stride` method? I have never seen it before.
# And it is not documented on https://ruby-doc.org/
# Let's investigate:
[].class.ancestors
#=> [
# Array,
# Enumerable,
# CoreExtensions::EnumerableExtensions::EnumerableWithStride,
# Object,
# Kernel,
# BasicObject
# ]
# So, we're confused about a method named `stride` and we
# found a module whose name includes `Stride`.
# We can reasonably guess that somewhere in the system,
# there must be a file named
# `core_extensions/enumerable_extensions/enumerable_with_stride.rb`.
# Or, we could ask the method directly:
meth = [].method(:stride)
meth.owner
#=> CoreExtensions::EnumerableExtensions::EnumerableWithStride
meth.source_location
#=> [
# 'core_extensions/enumerable_extensions/enumerable_with_stride.rb',
# 6
# ]
For an empty array, nothing happens:
[].stride(2, &method(:p))
#=> []
stride just returns self (just like each does) and the block is never executed.
For a non-empty array, we get an infinite stream of values:
x.stride(&method(:p))
# 0
# 1
# 2
# 3
# 4
# 0
# 1
# …
x.stride(2, &method(:p))
# 0
# 2
# 4
# 1
# 3
# 0
# 2
# …
x.stride(8, &method(:p))
# 0
# 3
# 1
# 4
# 2
# 0
# 3
# …
The nice thing about this infinite stream of values is that we, as the consumer can freely choose how many elements we want. For example, if I want 10 elements, I simply take 10 elements:
x.stride(3).take(10)
#=> [0, 3, 1, 4, 2, 0, 3, 1, 4, 2]
This works because, like all well-behaved iterators, our stride method returns an Enumerator in case no block is supplied:
enum = x.stride(2)
#=> #<Enumerator: ...>
enum.next
#=> 0
enum.next
#=> 2
enum.next
#=> 4
enum.next
#=> 1
enum.next
#=> 3
enum.next
#=> 0
enum.next
#=> 2
So, if we want to implement the requirement "until all the elements of the array are printed":
I am asked to write some code in Ruby that iterates over every n-th element of an array and prints it until all elements of the array are printed.
We could implement that something like this:
x.stride.take(x.length).each(&method(:p))
x.stride(2).take(x.length).each(&method(:p))
x.stride(8).take(x.length).each(&method(:p))
This is a pretty simplistic implementation, though. Here, we simply print as many elements as there are elements in the original array.
We could implement a more sophisticated logic using Enumerable#take_while that keeps track of which elements have been printed and which haven't, and only stops if all elements are printed. But we can easily prove that after x.length iterations either all elements have been printed or there will never be all elements printed (if the stride size is an integral multiple of the array length or vice versa). So, this should be fine.
This almost does what I think you want but breaks if the step is array.length + 1 array.length (but you mention that we should assume the stride is not a multiply of the array length).
class Array
def exhaustive_stride(step)
(self * step).map.with_index do |element, index|
next element if index == 0
element if index % step == 0
end.compact
end
end
x.exhaustive_stride 1
#=> [0, 1, 2, 3, 4]
x.exhaustive_stride 2
#=> [0, 2, 4, 1, 3]
x.exhaustive_stride 8
#=> [0, 3, 1, 4, 2]
[].exhaustive_stride 2
#=> []
Using the example array, it breaks when the stride is 5.
[0,1,2,3,4].exhaustive_stride 5
#=> [0, 0, 0, 0, 0]
Note
This works but the intermediate array makes it highly inefficient. Consider other answers.
Here's another solution that uses recursion. Not the most efficient but one way of doing it.
class Array
def exhaustive_stride(x, r = [])
return [] if self.empty?
r << self[0] if r.empty?
while x > self.length
x -= self.length
end
r << self[x]
x += x
return r if r.count == self.count
stride(x, r)
end
end
[0,1,2,3,4].exhaustive_stride 1
#=> [0, 1, 2, 4, 3]
[0,1,2,3,4].exhaustive_stride 2
#=> [0, 2, 4, 3, 1]
[0,1,2,3,4].exhaustive_stride 8
#=> [0, 3, 1, 2, 4]
[].exhaustive_stride 2
#=> []
[0,1,2,3,4].exhaustive_stride 100_000_001
#=> [0, 1, 2, 4, 3]
This would work:
def stride(ary, step)
raise ArgumentError unless step.gcd(ary.size) == 1
Array.new(ary.size) { |i| ary[(i * step) % ary.size] }
end
Example:
x = [0, 1, 2, 3, 4]
stride(x, 1) #=> [0, 1, 2, 3, 4]
stride(x, 2) #=> [0, 2, 4, 1, 3]
stride(x, 8) #=> [0, 3, 1, 4, 2]
stride(x, -1) #=> [0, 4, 3, 2, 1]
First of all, the guard clause checks whether step and ary.size are coprime to ensure that all elements can be visited via step.
Array.new(ary.size) creates a new array of the same size as the original array. The elements are then retrieved from the original array by multiplying the element's index by step and then performing a modulo operation using the array's size.
Having % arr.size is equivalent to fetching the elements from a cyclic array, e.g. for a step value of 2:
0 1 2 3 4
| | | | |
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ...
To turn this into an instance method for Array you merely replace ary with self (which can be omitted most of the time):
class Array
def stride(step)
raise ArgumentError unless step.gcd(size) == 1
Array.new(size) { |i| self[(i * step) % size] }
end
end

Ruby combined comparison operator (<=>) and min / max / minmax functions

I understand #max, #min, #minmax. I understand <=>. But how does it work in a block within one of those functions?
That is, what is happening in the third line below? What is <=> doing in #min?
a = %w(albatross dog horse)
a.min #=> "albatross"
a.min { |a, b| a.length <=> b.length } #=> "dog"
example from http://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-min
What behavior would it have for an array of numbers?
As you've probably already seen, the documentation for the min method says:
min(n) → array
min(n) {| a,b | block } → array
Returns the object in enum with the minimum value. The first form
assumes all objects implement Comparable; the second uses the block to
return a <=> b.
This means that, in the first form, min is calling the <=> method on objects in the array and using the result to determine which element is the smallest.
In the second form, min instead calls the block with both of the elements it wants to compare, and uses the block's return value to determine which element is the smallest. Basically, it's using the block as if it were an implementation of the <=> operator. So x.min {|a,b| a <=> b } would be equivalent to x.min.
In the example given (a.min { |a, b| a.length <=> b.length } #=> "dog"), this means that instead of comparing each element to determine sort order, it's comparing the lengths of each element to make that determination. Since "dog" is the shortest string in the list, that's the value that gets returned by min. max, minmax, and sort behave similarly.
Note that the example there is a bit contrived, since you could just use min_by in that situation to achieve the same result with simpler code: a.min_by { |x| x.length }. If you want more fine-grained control though when determining sort order, using min with a block might be appropriate.
What behavior would it have for an array of numbers?
min behaves the same way regardless of what the array contains. In this case though using the block { |a, b| a.length <=> b.length } wouldn't work since numbers don't have a length method on them. Here's a better example for numbers, which sorts by smallest to biggest, but always counts odd numbers as being bigger than even numbers:
[2, 10, 9, 7, 6, 1, 5, 3, 8, 4].sort do |a, b|
if a.odd? && b.even?
1
elsif a.even? && b.odd?
-1
else
a <=> b
end
end
Result:
[2, 4, 6, 8, 10, 1, 3, 5, 7, 9]
Notice how even numbers are sorted before odd numbers in the final array? That's the result of the block we passed to sort. The behavior is similar for min, max, and minmax.
min passes two elements a and b from the array to the block and the block is expected to return -1, 0, or +1 depending on whether a is less than, equal to, or greater than b. The "spaceship" operator <=> returns these -1, 0, or +1 values.
The algorithm is easy. Given a comparison function:
cmp = -> (a, b) { a.length <=> b.length }
We start by comparing the 1st with the 2nd element:
cmp.call 'albatros', 'dog'
#=> 1
1 means 'albatros' is greater than 'dog'. We continue with the lesser value, i.e. 'dog' and compare it with the 3rd element:
cmp.call 'dog', 'horse'
#=> -1
-1 means 'dog' is less than 'horse'. There are no more elements, so 'dog' is the result.
You could also implement this algorithm in Ruby:
def my_min(ary)
ary.inject { |min, x| yield(x, min) == -1 ? x : min }
end
ary = %w(albatross dog horse)
my_min(ary) { |a, b| a.length <=> b.length }
#=> "dog"

Alphabetical sorting of an array without using the sort method

I have been working through Chris Pine's tutorial for Ruby and am currently working on a way to sort an array of names without using sort.
My code is below. It works perfectly but is a step further than I thought I had got!
puts "Please enter some names:"
name = gets.chomp
names = []
while name != ''
names.push name
name = gets.chomp
end
names.each_index do |first|
names.each_index do |second|
if names[first] < names[second]
names[first], names[second] = names[second], names[first]
end
end
end
puts "The names you have entered in alphabetical order are: " + names.join(', ')
It is the sorting that I am having trouble getting my head around.
My understanding of it is that each_index would look at the position of each item in the array. Then the if statement takes each item and if the number is larger than the next it swaps it in the array, continuing to do this until the biggest number is at the start. I would have thought that this would just have reversed my array, however it does sort it alphabetically.
Would someone be able to talk me through how this algorithm is working alphabetically and at what point it is looking at what the starting letters are?
Thanks in advance for your help. I'm sure it is something very straightforward but after much searching I can't quite figure it out!
I think the quick sort algorithm is one of the easier ones to understand:
def qsort arr
return [] if arr.length == 0
pivot = arr.shift
less, more = arr.partition {|e| e < pivot }
qsort(less) + [pivot] + qsort(more)
end
puts qsort(["George","Adam","Michael","Susan","Abigail"])
The idea is that you pick an element (often called the pivot), and then partition the array into elements less than the pivot and those that are greater or equal to the pivot. Then recursively sort each group and combine with the pivot.
I can see why you're puzzled -- I was too. Look at what the algorithm does at each swap. I'm using numbers instead of names to make the order clearer, but it works the same way for strings:
names = [1, 2, 3, 4]
names.each_index do |first|
names.each_index do |second|
if names[first] < names[second]
names[first], names[second] = names[second], names[first]
puts "[#{names.join(', ')}]"
end
end
end
=>
[2, 1, 3, 4]
[3, 1, 2, 4]
[4, 1, 2, 3]
[1, 4, 2, 3]
[1, 2, 4, 3]
[1, 2, 3, 4]
In this case, it started with a sorted list, then made a bunch of swaps, then put things back in order. If you only look at the first couple of swaps, you might be fooled into thinking that it was going to do a descending sort. And the comparison (swap if names[first] < names[second]) certainly seems to imply a descending sort.
The trick is that the relationship between first and second is not ordered; sometimes first is to the left, sometimes it's to the right. Which makes the whole algorithm hard to reason about.
This algorithm is, I guess, a strange implementation of a Bubble Sort, which I normally see implemented like this:
names.each_index do |first|
(first + 1...names.length).each do |second|
if names[first] > names[second]
names[first], names[second] = names[second], names[first]
puts "[#{names.join(', ')}]"
end
end
end
If you run this code on the same array of sorted numbers, it does nothing: the array is already sorted so it swaps nothing. In this version, it takes care to keep second always to the right of first and does a swap only if the value at first is greater than the value at second. So in the first pass (where first is 0), the smallest number winds up in position 0, in the next pass the next smallest number winds up in the next position, etc.
And if you run it on array that reverse sorted, you can see what it's doing:
[3, 4, 2, 1]
[2, 4, 3, 1]
[1, 4, 3, 2]
[1, 3, 4, 2]
[1, 2, 4, 3]
[1, 2, 3, 4]
Finally, here's a way to visualize what's happening in the two algorithms. First the modified version:
0 1 2 3
0 X X X
1 X X
2 X
3
The numbers along the vertical axis represent values for first. The numbers along the horizontal represent values for second. The X indicates a spot at which the algorithm compares and potentially swaps. Note that it's just the portion above the diagonal.
Here's the same visualization for the algorithm that you provided in your question:
0 1 2 3
0 X X X X
1 X X X X
2 X X X X
3 X X X X
This algorithm compares all the possible positions (pointlessly including the values along the diagonal, where first and second are equal). The important bit to notice, though, is that the swaps that happen below and to the left of the diagonal represent cases where second is to the left of first -- the backwards case. And also note that these cases happen after the forward cases.
So essentially, what this algorithm does is reverse sort the array (as you had suspected) and then afterwards forward sort it. Probably not really what was intended, but the code sure is simple.
Your understanding is just a bit off.
You said:
Then the if statement takes each item and if the number is larger than the next it swaps it in the array
But this is not what the if statement is doing.
First, the two blocks enclosing it are simply setting up iterators first and second, which each count from the first to the last element of the array each time through the block. (This is inefficient but we'll leave discussion of efficient sorting for later. Or just see Brian Adkins' answer.)
When you reach the if statement, it is not comparing the indices themselves, but the names which are at those indices.
You can see what's going on by inserting this line just before the if. Though this will make your program quite verbose:
puts "Comparing names[#{first}] which is #{names[first]} to names[#{second}] which is #{names[second]}..."
Alternatively, you can create a new array and use a while loop to append the names in alphabetical order. Delete the elements that have been appended in the loop until there are no elements left in the old array.
sorted_names = []
while names.length!=0
sorted_names << names.min
names.delete(names.min)
end
puts sorted_names
This is the recursive solution for this case
def my_sort(list, new_array = nil)
return new_array if list.size <= 0
if new_array == nil
new_array = []
end
min = list.min
new_array << min
list.delete(min)
my_sort(list, new_array)
end
puts my_sort(["George","Adam","Michael","Susan","Abigail"])
Here is my code to sort items in an array without using the sort or min method, taking into account various forms of each item (e.g. strings, integers, nil):
def sort(objects)
index = 0
sorted_objects = []
while index < objects.length
sorted_item = objects.reduce do |min, item|
min.to_s > item.to_s ? item : min
end
sorted_objects << sorted_item
objects.delete_at(objects.find_index(sorted_item))
end
index += 1
sorted_objects
end
words_2 = %w{all i can say is that my life is pretty plain}
p sort(words_2)
=> ["all", "can", "i", "is", "is", "life", "my", "plain", "pretty", "say", "that"]
mixed_array_1 = ["2", 1, "5", 4, "3"]
p sort(mixed_array_1)
=> [1, "2", "3", 4, "5"]
mixed_array_2 = ["George","Adam","Michael","Susan","Abigail", "", nil, 4, "5", 100]
p sort(mixed_array_2)
=> ["", nil, 100, 4, "5", "Abigail", "Adam", "George", "Michael", "Susan"]

Each with index with object in Ruby

I am trying to iterate over an array and conditionally increment a counter. I am using index to compare to other array's elements:
elements.each_with_index.with_object(0) do |(element, index), diff|
diff += 1 unless other[index] == element
end
I can't get diff to change value even when changing it unconditionally.
This can be solved with inject:
elements.each_with_index.inject(0) do |diff, (element, index)|
diff += 1 unless other[index] == element
diff
end
But I am wondering if .each_with_index.with_object(0) is a valid construction and how to use it?
From ruby docs for each_with_object
Note that you can’t use immutable objects like numbers, true or false
as the memo. You would think the following returns 120, but since the
memo is never changed, it does not.
(1..5).each_with_object(1) { |value, memo| memo *= value } # => 1
So each_with_object does not work on immutable objects like integer.
You want to count the number of element wise differences, right?
elements = [1, 2, 3, 4, 5]
other = [1, 2, 0, 4, 5]
# ^
I'd use Array#zip to combine both arrays element wise and Array#count to count the unequal pairs:
elements.zip(other).count { |a, b| a != b } #=> 1

Ruby inject with index and brackets

I try to clean my Code. The first Version uses each_with_index. In the second version I tried to compact the code with the Enumerable.inject_with_index-construct, that I found here.
It works now, but seems to me as obscure as the first code.
Add even worse I don't understand the brackets around element,index in
.. .inject(groups) do |group_container, (element,index)|
but they are necessary
What is the use of these brackets?
How can I make the code clear and readable?
FIRST VERSION -- WITH "each_with_index"
class Array
# splits as good as possible to groups of same size
# elements are sorted. I.e. low elements go to the first group,
# and high elements to the last group
#
# the default for number_of_groups is 4
# because the intended use case is
# splitting statistic data in 4 quartiles
#
# a = [1, 8, 7, 5, 4, 2, 3, 8]
# a.sorted_in_groups(3) # => [[1, 2, 3], [4, 5, 7], [8, 8]]
#
# b = [[7, 8, 9], [4, 5, 7], [2, 8]]
# b.sorted_in_groups(2) {|sub_ary| sub_ary.sum } # => [ [[2, 8], [4, 5, 7]], [[7, 8, 9]] ]
def sorted_in_groups(number_of_groups = 4)
groups = Array.new(number_of_groups) { Array.new }
return groups if size == 0
average_group_size = size.to_f / number_of_groups.to_f
sorted = block_given? ? self.sort_by {|element| yield(element)} : self.sort
sorted.each_with_index do |element, index|
group_number = (index.to_f / average_group_size).floor
groups[group_number] << element
end
groups
end
end
SECOND VERSION -- WITH "inject" AND index
class Array
def sorted_in_groups(number_of_groups = 4)
groups = Array.new(number_of_groups) { Array.new }
return groups if size == 0
average_group_size = size.to_f / number_of_groups.to_f
sorted = block_given? ? self.sort_by {|element| yield(element)} : self.sort
sorted.each_with_index.inject(groups) do |group_container, (element,index)|
group_number = (index.to_f / average_group_size).floor
group_container[group_number] << element
group_container
end
end
end
What is the use of these brackets?
It's a very nice feature of ruby. I call it "destructuring array assignment", but it probably has an official name too.
Here's how it works. Let's say you have an array
arr = [1, 2, 3]
Then you assign this array to a list of names, like this:
a, b, c = arr
a # => 1
b # => 2
c # => 3
You see, the array was "destructured" into its individual elements. Now, to the each_with_index. As you know, it's like a regular each, but also returns an index. inject doesn't care about all this, it takes input elements and passes them to its block as is. If input element is an array (elem/index pair from each_with_index), then we can either take it apart in the block body
sorted.each_with_index.inject(groups) do |group_container, pair|
element, index = pair
# or
# element = pair[0]
# index = pair[1]
# rest of your code
end
Or destructure that array right in the block signature. Parentheses there are necessary to give ruby a hint that this is a single parameter that needs to be split in several.
Hope this helps.
lines = %w(a b c)
indexes = lines.each_with_index.inject([]) do |acc, (el, ind)|
acc << ind - 1 if el == "b"
acc
end
indexes # => [0]
What is the use of these brackets?
To understand the brackets, first you need to understand how destruction works in ruby. The simplest example I can think of this this:
1.8.7 :001 > [[1,3],[2,4]].each do |a,b|
1.8.7 :002 > puts a, b
1.8.7 :003?> end
1
3
2
4
You should know how each function works, and that the block receives one parameter. So what happens when you pass two parameters? It takes the first element [1,3] and try to split (destruct) it in two, and the result is a=1 and b=3.
Now, inject takes two arguments in the block parameter, so it is usually looks like |a,b|. So passing a parameter like |group_container, (element,index)| we are in fact taking the first one as any other, and destructing the second in two others (so, if the second parameter is [1,3], element=1 and index=3). The parenthesis are needed because if we used |group_container, element, index| we would never know if we are destructing the first or the second parameter, so the parenthesis there works as disambiguation.
9In fact, things works a bit different in the bottom end, but lets hide this for this given question.)
Seems like there already some answers given with good explanation. I want to add some information regards the clear and readable.
Instead of the solution you chose, it is also a possibility to extend Enumerable and add this functionality.
module Enumerable
# The block parameter is not needed but creates more readable code.
def inject_with_index(memo = self.first, &block)
skip = memo.equal?(self.first)
index = 0
self.each_entry do |entry|
if skip
skip = false
else
memo = yield(memo, index, entry)
end
index += 1
end
memo
end
end
This way you can call inject_with_index like so:
# m = memo, i = index, e = entry
(1..3).inject_with_index(0) do |m, i, e|
puts "m: #{m}, i: #{i}, e: #{e}"
m + i + e
end
#=> 9
If you not pass an initial value the first element will be used, thus not executing the block for the first element.
In case, someone is here from 2013+ year, you have each_with_object and with_index for your needs:
records.each_with_object({}).with_index do |(record, memo), index|
memo[record.uid] = "#{index} in collection}"
end

Resources