Home > Back-end >  ruby array group by multiple element values
ruby array group by multiple element values

Time:09-22

I tried searching for an answer but nothing I found has worked...

I have an array that looks like this... [["10", "20", "1"], ["10", "30", "1"], ["10", "30", "1"]] and I'd like to group them by both the first and second elements.

Result [[["10", "20", "1", 1]], [["10", "30", "1", 2], ["10", "30", "1"]]]

From what I found I've tried these...

list.group_by{|w| w[3]}.values do |v1| v1.group_by{|l| l[4]} end

list.group_by{|w| w; [w[3], w[4]]}.map{|k, v| [k.first, k.last, v.length]}

This works but only takes one of the elements into account when grouping...

sub_group=list.group_by{|w| [w[3], w[4]]}.values

sub_group.each{|group| group[0] << group.length}

CodePudding user response:

You could group the array to get a count of elements, then map the values by checking their index, when it's 0 then you add the total elements;

[["10", "20", "1"], ["10", "30", "1"], ["10", "30", "1"]]
  .group_by(&:itself)
  .values
  .map do |values|
    values.map.with_index do |value, i|
      next value   [values.length] if i.zero?

      value
    end
  end
# [[["10", "20", "1", 1]], [["10", "30", "1", 2], ["10", "30", "1"]]]

CodePudding user response:

With Enumerable#tally and Enumerable#each_with_object

[["10", "20", "1"], ["10", "30", "1"], ["10", "30", "1"]]
  .tally
  .each_with_object([]) do |(item, count), new_ary|
    new_item = item.dup
    new_item << count
    
    new_ary << [new_item]
    (count - 1).times { new_ary.last << item }
  end

# => [[["10", "20", "1", 1]], [["10", "30", "1", 2], ["10", "30", "1"]]]

You can also use Array#flatten! instead first two lines inside each_with_object. In this case in times you need item[..-2]

[["10", "20", "1"], ["10", "30", "1"], ["10", "30", "1"]]
  .tally
  .each_with_object([]) do |item, new_ary|
    item.flatten!
    
    new_ary << [item]
    (item.last - 1).times { new_ary.last << item[..-2] }
  end

# => [[["10", "20", "1", 1]], [["10", "30", "1", 2], ["10", "30", "1"]]]
  • Related