简体   繁体   中英

Merge arrays of hashes into one array, and then group all the hashes based on matching id's

I have a few arrays (let's call them "original arrays"). Each array contains hashes, and inside each hash I have data from a received email. For example an email address, a name, etc. I also have a uid, which is the unique identifier on the received email. There will be a lot of duplication between the original arrays, and the more the arrays have in common the better (in the perfect world they should contain the same emails and the same email data).

Input sample:

[[{:from_address=>"one@example.com",
   :to=>"one@example.com",
   :subject=>"Some subject regarding order 12198",
   :datetime=>Sat, 27 Jul 2013 08:48:44 +0000,
   :uid=>15065,
   :extraction_strategy=>1,
   :result=>{:order_id=>"12198", :mail_address=>nil, :name=>"Dr. Evil"}},
  {:from_address=>"one@example.com",
   :to=>"one@example.com",
   :subject=>"Some subject regarding order 12199",
   :datetime=>Sat, 27 Jul 2013 08:48:48 +0000,
   :uid=>15066,
   :extraction_strategy=>1,
   :result=>{:order_id=>"12199", :mail_address=>nil, :name=>nil}}],
 [{:from_address=>"one@example.com",
   :to=>"one@example.com",
   :subject=>"Some subject regarding order 12197",
   :datetime=>Sat, 27 Jul 2013 08:22:48 +0000,
   :uid=>15064,
   :extraction_strategy=>2,
   :result=>{:order_id=>"12197", :mail_address=>"three@example.com", :name=>"Batman"}},
  {:from_address=>"one@example.com",
   :to=>"one@example.com",
   :subject=>"Some subject regarding order 12199",
   :datetime=>Sat, 27 Jul 2013 08:48:48 +0000,
   :uid=>15066,
   :extraction_strategy=>2,
   :result=>{:order_id=>"12199", :mail_address=>"two@example.com", :name=>"James Bond"}}]]

I now want to reorder all this so I get one new array (let's call it a "1st level array"). Inside the 1st level array I want "2nd level arrays", each containing emails with matching uid's. So if an email from one of the original arrays has the same uid as an email in one of the other original arrays the two emails should be put into the same new 2nd level array.

Output sample:

   [[
    [{:from_address=>"one@example.com",
      :to=>"one@example.com",
      :subject=>"Some subject regarding order 12197",
      :datetime=>Sat, 27 Jul 2013 08:22:48 +0000,
      :uid=>15064,
      :extraction_strategy=>2,
      :result=>{:order_id=>"12197", :mail_address=>"three@example.com", :name=>"Batman"}}],
    [{:from_address=>"one@example.com",
      :to=>"one@example.com",
      :subject=>"Some subject regarding order 12198",
      :datetime=>Sat, 27 Jul 2013 08:48:44 +0000,
      :uid=>15065,
      :extraction_strategy=>1,
      :result=>{:order_id=>"12198", :mail_address=>nil, :name=>"Dr. Evil"}}],
    [{:from_address=>"one@example.com",
      :to=>"one@example.com",
      :subject=>"Some subject regarding order 12199",
      :datetime=>Sat, 27 Jul 2013 08:48:48 +0000,
      :uid=>15066,
      :extraction_strategy=>1,
      :result=>{:order_id=>"12199", :mail_address=>"two@example.com", :name=>"James Bond"}},
     {:from_address=>"one@example.com",
      :to=>"one@example.com",
      :subject=>"Some subject regarding order 12199",
      :datetime=>Sat, 27 Jul 2013 08:48:48 +0000,
      :uid=>15066,
      :extraction_strategy=>2,
      :result=>{:order_id=>"12199", :mail_address=>nil, :name=>nil}}]
   ]]

I can only come up with solutions that requires a lot of loops and repetition, but as the arrays can get quite huge I need a efficient concise routine for this. Can anyone help me out?

well, two nested loops and a map...

a = [[{:from_address=>"one@example.com",
       :to=>"one@example.com",
       :subject=>"Some subject regarding order 12198",
       :datetime=>"Sat, 27 Jul 2013 08:48:44 +0000",
       :uid=>15065,
       :extraction_strategy=>1,
       :result=>{:order_id=>"12198", :mail_address=>nil, :name=>"Dr. Evil"}},
      {:from_address=>"one@example.com",
       :to=>"one@example.com",
       :subject=>"Some subject regarding order 12199",
       :datetime=>"Sat, 27 Jul 2013 08:48:48 +0000",
       :uid=>15066,
       :extraction_strategy=>1,
       :result=>{:order_id=>"12199", :mail_address=>nil, :name=>nil}}],
     [{:from_address=>"one@example.com",
       :to=>"one@example.com",
       :subject=>"Some subject regarding order 12197",
       :datetime=>"Sat, 27 Jul 2013 08:22:48 +0000",
       :uid=>15064,
       :extraction_strategy=>2,
       :result=>{:order_id=>"12197", :mail_address=>"three@example.com", :name=>"Batman"}},
      {:from_address=>"one@example.com",
       :to=>"one@example.com",
       :subject=>"Some subject regarding order 12199",
       :datetime=>"Sat, 27 Jul 2013 08:48:48 +0000",
       :uid=>15066,
       :extraction_strategy=>2,
       :result=>{:order_id=>"12199", :mail_address=>"two@example.com", :name=>"James Bond"}}]]

       result  = Hash.new {|h,k| h[k] = [] }
       a.each { |b| b.each { |h| result[h[:uid]] << h } }
       result = result.map { |k, v| v }

...but note that to get this to work I had to change the datetime fields into strings. Somebody cleverer than me might be able to figure out how to get around that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM