/ Tags: RUBY-CODE / Categories: SOLUTIONS

Extract Unique Values From An Array Of Hashes By A Key In Ruby

You have a list of records and you want every distinct value of one field — all the account ids in a batch, every category present in a result set, the set of statuses currently in use. It is a map followed by a uniq, with a couple of refinements worth knowing.

Description

map { |h| h[:key] }.uniq is the direct form. filter_map does both in one pass and drops nils, which is usually what you want when the key is optional. For a large collection where you only need membership testing afterwards, build a Set instead — uniq is O(n) but Array#include? is O(n) per lookup while Set#include? is effectively constant. To deduplicate case-insensitively or on a normalized form, pass a block to uniq rather than mutating the source data.

Sample input:

  records = [
    { id: 1, category: "ruby",  author: "Ada" },
    { id: 2, category: "rails", author: "Grace" },
    { id: 3, category: "ruby",  author: nil }
  ]


Sample Output:

  # => ["ruby", "rails"]

Answer

  records.map { |r| r[:category] }.uniq
  # => ["ruby", "rails"]

  # One pass, and nils dropped
  records.filter_map { |r| r[:author] }.uniq
  # => ["Ada", "Grace"]

  # Symbol-to-proc when the records respond to the method
  orders.map(&:status).uniq

  # Case-insensitive distinct values
  records.filter_map { |r| r[:category] }.uniq(&:downcase)

  # Set — much faster for repeated membership checks
  require "set"
  categories = records.filter_map { |r| r[:category] }.to_set
  categories.include?("ruby")   # => true

  # Distinct values with their counts
  records.filter_map { |r| r[:category] }.tally
  # => { "ruby" => 2, "rails" => 1 }

  # Distinct across two keys combined
  records.map { |r| [r[:category], r[:author]] }.uniq

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