Ruby inject with index and brackets

18,640

Solution 1

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.

Solution 2

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]
Share:
18,640

Related videos on Youtube

ovhaag
Author by

ovhaag

Updated on September 15, 2022

Comments

  • ovhaag
    ovhaag over 1 year

    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
    
  • ovhaag
    ovhaag about 11 years
    Now I understand. Great explanation. Thanks a lot.