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
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
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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With