3

I have an array of arrays in Ruby:

price_list = [
  ['Brand-1', 'Model-1', 100.00],
  ['Brand-1', 'Model-2', 200.00],
  ['Brand-2', 'Model-1', 10.00],
  ['Brand-2', 'Model-2', 20.00],
  ['Brand-1', 'Model-1', 110.00],
  ['Brand-1', 'Model-2', 190.00],
  ['Brand-1', 'Model-3', 300.00],
  ...
  ['Brand-n', 'Model-n', 1234.00]
]

And I need to create new array with only unique products and minimal prices. Something like this:

new_price_list = [
  ['Brand-1', 'Model-1', 100.00],
  ['Brand-2', 'Model-1', 10.00],
  ['Brand-2', 'Model-2', 20.00],
  ['Brand-1', 'Model-2', 190.00],
  ['Brand-1', 'Model-3', 300.00],
  ...
  ['Brand-n', 'Model-n', 1234.00]
]

What is a fastest and most beautiful way to do this in Ruby?

4 Answers 4

5

Group by key (brand+model) and then get the minimum price on the grouped arrays:

prices = [
  ['Brand-1', 'Model-1', 100.00],
  ['Brand-1', 'Model-2', 200.00],
  ['Brand-2', 'Model-1', 10.00],
  ['Brand-2', 'Model-2', 20.00],
  ['Brand-1', 'Model-1', 110.00],
  ['Brand-1', 'Model-2', 190.00],
  ['Brand-1', 'Model-3', 300.00],
]

grouped = prices.group_by { |brand, model, price| [brand, model] }
grouped.values.map { |grouped_prices| grouped_prices.min_by(&:last) }

Output:

[["Brand-1", "Model-2", 190.0],
 ["Brand-1", "Model-3", 300.0],
 ["Brand-2", "Model-1", 10.0],
 ["Brand-2", "Model-2", 20.0],
 ["Brand-1", "Model-1", 100.0]]
Sign up to request clarification or add additional context in comments.

Comments

1
items = Hash.new()
price_list.each{|brand,model,price|
     item=items[brand+model]
     items[brand+model]=[brand,model,price] if (!item||item[2]>price)
}

1 Comment

I think it is possible to make code shorter than that and more beautiful.
1

If you dont need to sort by brand and model, this can be done like this:

new_price_list = price_list.sort_by { |brand,model,price| price }.uniq {|brand, model, price| [brand, model] }

If you want it also sorted, you have to sort again

new_price_list = price_list.sort_by { |brand,model,price| brand + model }.sort_by { |brand,model,price| price }.uniq {|brand, model, price| [brand, model] }

Edit: uniq with block will work only in ruby 1.9

Comments

0

using new_price_list = price_list & Array.new(price_list) should return a new array with all elements unique to the two sets according to the api docs

Set Intersection—Returns a new array containing elements common to the two arrays, with no duplicates.

1 Comment

The second array in his question is the desired result.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.