开发者

Create an intersection of two key's values, if keys in 2 seperate hashes are equal. Ruby

I am trying to create an intersection of the values of hash1 with those of hash2, if those values share the same key. Here is my code so far. I am able to generate two hashes --> data and data1.

#!/usr/bin/env ruby

require 'pp'
require 'set'
data = {}
File.read(ARGV[0]).each do |l|
  l.chomp!
  key, value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12 = l.split(/\s+/)
  data[key] ||= {}
  values = [value1, value2, value3, value4, value5, value6, value7, value8, value9, value10, value11, value12]
  data[key] = values.compact!

end

data1 = {}
File.read(ARGV[1]).each do |l|
  l.chomp!
  value = l.split(/\s+/)
  data1[value[0]] ||= {}
  data1[value[0]] = [value] 
end

So, my main goal is for each key in hash1, keep only those values that also are present at that identical key in hash2, otherwise remove those values from hash1. I am not concerned with any keys present in Hash2 that are not present in Hash1, btw.

I know arrays can be intersected using "&" and "set", though I have not been able to accomplish this in my script so far.

Any advice would b开发者_Python百科e great. Thanks.

For Theo:

Yes.

hash1 { alpha: [a,b,c,d,e], bravo: [f,g,h,i,j], charlie: [k,l,m,n,o], delta:[p,r]}

hash2 { alpha: [a,c,q,z], bravo: [z,x], charlie: [k,l,m,n]}

So, the intersection would look like this.

hash3 { alpha: [a,c], bravo:[nil], charlie: [k,l,m,n]}


For a regular intersection of two hashes do:

Hash[h1.to_a & h2.to_a]

But your case is a little bit different. You can get the intersection you are looking for with this code:

hash1 = {:alpha => [:a,:b,:c,:d,:e], :bravo => [:f,:g,:h,:i,:j], :charlie => [:k,:l,:m,:n,:o], :delta => [:p,:r]}
hash2 = {:alpha => [:a,:c,:q,:z], :bravo => [:z,:x], :charlie => [:k,:l,:m,:n]}

common_keys = hash1.keys & hash2.keys 
  # => [:alpha, :bravo, :charlie]
intersection = common_keys.map { |k| [k, hash1[k] & hash2[k]] } 
  # => [[:alpha, [:a, :c]], [:bravo, []], [:charlie, [:k, :l, :m, :n]]]
intersection = intersection.reject { |k, v| v.empty? } 
  # => [[:alpha, [:a, :c]], [:charlie, [:k, :l, :m, :n]]]
Hash[intersection]
  # => {:alpha=>[:a, :c], :charlie=>[:k, :l, :m, :n]}

Your example includes :bravo => [nil], but I think that is an error since nil is not a common element between the :bravo key in hash1 and hash2, so it doesn't make sense. If you want an empty list for keys that are in hash1 and hash2 but have no common elements in their value lists you can remove the third line, which otherwise removes those.


data  = { a: [11], b: [22, 222], c: [33] }
data2 = { b: [222, 2222], d: [4444] }

Hash[data.map {|k, v| if data2[k] then [k, v & data2[k]] end }.compact]
# => { b: [222] }


def merge_hash(hash1, hash2)
  result = {}

  hash1.keys.each do |k|
    result[k] = hash1[k] & hash2[k] unless hash2[k].nil?
  end
  result
end


Hash[h2.collect { |k,v| h1[k] ? [k, h1[k] & h2[k]] : [] }]

Additionally, you check the size of h1.keys compared to h2.keys first and then iterate over the smaller one first. It loses a bit of the clarity of the above, but it will perform a lot better for larger hashes with a disparity in sizes.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜