How to merge 2 arrays where value in one matches a value in another with different key in Ruby

I have an array that contains other arrays of items with prices but when one has a sale a new item is created How do I merge or pull value from one to the other to make 1 array so that the sale price replaces the non sale but contains the original price?


items=[{"id": 123, "price": 100, "sale": false},{"id":456,"price":25,"sale":false},{"id":678, "price":75, "sale":true, "parent_price_id":123}]

Transform into:

items=[{"id":456,"price":25,"sale":false},{"id":678, "price":75, "sale":true, "parent_price_id":123, "original_price": 100}]

Stack Overflow Asked by Mike2414 on February 18, 2021

2 Answers

2 Answers

It's not the prettiest solution, but here's one way you can do it. I added a minitest spec to check it against the values you provided and it gives the answer you're hoping for.

require "minitest/autorun"

def merge_prices(prices)
  # Create a hash that maps the ID to the values
  price_map =
    .map do |price|
      [price[:id], price]
  # Create a result array which is initially duplicated from the original
  result = prices.dup
  result.each do |price|
    if price.key?(:parent_price)
      price[:original_price] = price_map[price[:parent_price]][:price]
      # Delete the original
      result.delete_if { |x| x[:id] == price[:parent_price] }

describe "Merge prices" do
  it "should work" do
    input = [
      {"id":123, "price": 100, "sale": false},
      {"id":456,"price":25,"sale": false},
      {"id":678, "price":75, "sale": true, "parent_price":123}
    expected_output = [
      {"id":456,"price":25,"sale": false},
      {"id":678, "price":75, "sale": true, "parent_price":123, "original_price": 100}
    assert_equal(merge_prices(input), expected_output)

Correct answer by Petro Podrezo on February 18, 2021

Let's being by defining items in an equivalent, but more familiar, way:

items = [
  [{:id=>123, :price=>100, :sale=>false}],
  [{:id=>456, :price=>25,  :sale=>false}],
  [{:id=>678, :price=>75,  :sale=>true, :parent_price=>123}]

with the desired return value being:

  {:id=>456, :price=>25, :sale=>false},
  {:id=>678, :price=>75, :sale=>true, :parent_price=>123,

I assume that h[:sale] #=> false for every element of items (a hash) g for which g[:parent_price] = h[:id].

A convenient first step is to create the following hash.

h = { |(h)| [h[:id], h] }.to_h
  #=> {123=>{:id=>123, :price=>100, :sale=>false},
  #    456=>{:id=>456, :price=>25, :sale=>false},
  #    678=>{:id=>678, :price=>75, :sale=>true, :parent_price=>123}}


  h.keys.each { |k| h[k][:original_price] =
    h.delete(h[k][:parent_price])[:price] if h[k][:sale] }
    #=> [123, 456, 678] (not used)

  h #=> {456=>{:id=>456, :price=>25, :sale=>false},
    #    678=>{:id=>678, :price=>75, :sale=>true, :parent_price=>123,
    #          :original_price=>100}} 

Notice that Hash#delete returns the value of the deleted key.

The last two steps are to extract the values from this hash and replace items with the resulting array of hashes:

    #=> [{:id=>456, :price=>25, :sale=>false},
    #    {:id=>678, :price=>75, :sale=>true, :parent_price=>123,
    #     :original_price=>100}] 

See Array#replace.

If desired we could combine these steps as follows.

items.replace( { |(h)| [h[:id], h] }.to_h.tap do |h|
    h.keys.each { |k| h[k][:original_price] =
      h.delete(h[k][:parent_price])[:price] if h[k][:sale] }
  #=> [{:id=>456, :price=>25, :sale=>false},
  #    {:id=>678, :price=>75, :sale=>true, :parent_price=>123,
  #     :original_price=>100}] 

See Object#tap.

Answered by Cary Swoveland on February 18, 2021

Add your own answers!

Related Questions

Pygame doesn’t play mp3 files tagged with mutagen

1  Asked on January 14, 2021 by droptop


Average by group for ‘n’ number of rows per group – R

2  Asked on January 14, 2021 by codemaster


Non consecutive combinations of array elements in R

4  Asked on January 13, 2021 by guest2341


How to mutate complex object with nested array with SWR?

1  Asked on January 13, 2021 by geraltdiesocke


Why do I not see a text box to add a menu item to a menustrip

1  Asked on January 13, 2021 by justsomeguytn


Alembic. ModuleNotFoundError in

2  Asked on January 13, 2021 by mroldsir


What type in c# is most like an expression in R and why?

1  Asked on January 12, 2021 by kirsten-greed


Difference between two loops

4  Asked on January 12, 2021 by mszros-zoltn


How can i do a request an external url?

0  Asked on January 12, 2021 by mikkylekyle


Ask a Question

Get help from others!

© 2022 All rights reserved.