beck03076
beck03076

Reputation: 3308

Ruby - Compare/merge 2 array of hashes based on 1 key

Lets say I have 2 array of hashes as follows,

local_todos = [{name: "abc", title: "abcdwer", api_id: "1234567", updated_at: "2013-22-12"},
{name: "abcd", title: "abcdwe", api_id: "098098", updated_at: "2013-22-11"},
{name: "abcde", title: "abcdqw", api_id: "345345", updated_at: "2013-22-18"},
{name: "abcdef", title: "abcder", api_id: "234456", updated_at: "2013-22-15"}]

google_tasks = [{name: "abc", title: "xxxxx", id: "1234567", updated: "2013-22-19"},
{name: "abcd", title: "zzzzz", id: "098098", updated: "2013-22-15"},
{name: "abcde", title: "abcdqw", id: "345345", updated: "2013-22-18"},
{name: "abcdef", title: "abcder", id: "234456", updated: "2013-22-15"}]

Now I want to, merge/compare/filter these 2 hashes purely based on api_id(local_todos) and id(google_tasks), so that only the id/api_id(both are the same value) that has a difference in the updated_at(local_todos) and updated(google_tasks) value is printed as the output.

Desired output will be like this,

["1234567", "098098"]

Because if you check those 2 ids has a different updated/updated_at values.

Any help?

Upvotes: 1

Views: 569

Answers (3)

Малъ Скрылевъ
Малъ Скрылевъ

Reputation: 16507

Just simple selection:

local_todos.map do | v1 |
   google_tasks.any? {|v2| v1[ :api_id ] == v2[ :id ] && v1[ :updated_at ] != v2[ :updated ] } && v1[ :api_id ] || nil
end.compact
# => ["1234567", "098098"]

To compare the code you are able to use the following code:

funcs =
[ proc { local_todos.map {|v1| google_tasks.any? {|v2| v1[ :api_id ] == v2[ :id ] && v1[ :updated_at ] != v2[ :updated ] } && v1[ :api_id ] || nil }.compact },
  proc {
   local_todos.inject([]) do |result,l_td|
    if found = google_tasks.detect {|g_td| g_td[:id] == l_td[:api_id] and  g_td[:updated] != l_td[:updated_at]}
        result << found[:id]
    end
    result
  end
},
]

def ctime func
   time = 0
   1000.times { time += Benchmark.measure { 1000.times { func.call } }.to_a[5].to_f }
   rtime = time /= 1000000
end

funcs.each {| func | p ctime( func ) }

# 3.9753190517425536e-05
# 4.056975722312927e-05

In my bench results the first code is slight faster.

Upvotes: 2

Jon
Jon

Reputation: 2793

local_todos.collect do |l_todo|
  google_tasks.collect do |g_task|
    l_todo[:api_id] if (l_todo[:api_id] == g_task[:id] && l_todo[:updated_at] != g_task[:updated])
  end.compact
end.flatten

Upvotes: 0

Pritesh Jain
Pritesh Jain

Reputation: 9146

local_todos.inject([]) do |result,l_td|
    if found = google_tasks.detect {|g_td| g_td[:id] == l_td[:api_id] and  g_td[:updated] != l_td[:updated_at]}
        result << found[:id]
    end
    result
end

Upvotes: 2

Related Questions