/ Tags: RUBY-CODE / Categories: SOLUTIONS

Remove Duplicate Hashes From An Array By A Specific Key In Ruby

uniq on an array of hashes compares whole hashes, so two records that share an id but differ in any other field both survive. Deduplicating by one key — an id, an email, a SKU — needs uniq with a block.

Description

uniq accepts a block; the block’s return value is what gets compared. uniq { |h| h[:id] } keeps the first occurrence of each id and discards later ones. To keep the last occurrence instead, reverse before and after, or build a hash keyed on the field and take values — the latter is clearer and does one pass. For composite keys, return an array from the block. For case-insensitive deduplication, normalize inside the block rather than mutating the data.

Sample input:

  records = [
    { id: 1, name: "Ada",   role: "admin" },
    { id: 2, name: "Grace", role: "user"  },
    { id: 1, name: "Ada L", role: "owner" }
  ]


Sample Output:

  # => [{ id: 1, name: "Ada", role: "admin" }, { id: 2, name: "Grace", role: "user" }]

Answer

  records.uniq { |r| r[:id] }
  # => keeps the first occurrence of each id

  # Keep the LAST occurrence instead
  records.reverse.uniq { |r| r[:id] }.reverse

  # Same thing, one pass, clearer intent
  records.each_with_object({}) { |r, acc| acc[r[:id]] = r }.values

  # Composite key
  records.uniq { |r| [r[:account_id], r[:sku]] }

  # Case-insensitive on a string key
  records.uniq { |r| r[:email].to_s.downcase.strip }

  # Which ids were duplicated?
  records.group_by { |r| r[:id] }
         .select { |_, group| group.size > 1 }
         .keys
  # => [1]

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