/ Tags: RUBY-CODE / Categories: SOLUTIONS

Flatten A Hash Of Arrays Into A Flat Array Of Hashes In Ruby

Grouped data — { "ruby" => [post1, post2], "rails" => [post3] } — often needs to be turned back into a flat list where each item carries its group. It is the inverse of group_by, and flat_map does it in one line.

Description

flat_map maps each key-value pair to an array and concatenates the results one level deep, which is exactly the shape needed here. Inside the block, map each element of the value array into a hash that includes the key. Using merge rather than mutation keeps the source data untouched. For the general case where values may or may not be arrays, wrap with Array() so a bare value is handled the same as a one-element array.

Sample input:

  grouped = {
    "ruby"  => [{ title: "Pattern matching" }, { title: "Ractor" }],
    "rails" => [{ title: "Turbo Streams" }]
  }


Sample Output:

  [{ category: "ruby",  title: "Pattern matching" },
   { category: "ruby",  title: "Ractor" },
   { category: "rails", title: "Turbo Streams" }]

Answer

  grouped.flat_map do |category, items|
    items.map { |item| item.merge(category: category) }
  end
  # => [{ title: "Pattern matching", category: "ruby" }, ...]

  # Tolerate non-array values
  grouped.flat_map do |category, items|
    Array(items).map { |item| item.merge(category: category) }
  end

  # Values are scalars rather than hashes
  { "ruby" => %w[a b], "rails" => %w[c] }.flat_map do |cat, tags|
    tags.map { |tag| { category: cat, tag: tag } }
  end
  # => [{category: "ruby", tag: "a"}, {category: "ruby", tag: "b"},
  #     {category: "rails", tag: "c"}]

  # The inverse — flat list back into a grouped hash
  flat = [{ category: "ruby", title: "A" }, { category: "rails", title: "B" }]
  flat.group_by { |h| h[:category] }
      .transform_values { |items| items.map { |i| i.except(:category) } }

  # Just the pairs, no wrapping hash
  grouped.flat_map { |cat, items| items.map { |i| [cat, i[:title]] } }

Learn More

cdrrazan

Rajan Bhattarai

Full Stack Software Developer! 💻 🏡 Grad. Student, MCS. 🎓 Class of '23. GitKraken Ambassador 🇳🇵 2021/22. Works with Ruby / Rails. Photography when no coding. Also tweets a lot at TW / @cdrrazan!

Read More