比较哈希的数组和打印期望&实际结果

时间:2016-11-10 12:47:29

标签: ruby hash

我有两个哈希数组:

actual = [{"column_name"=>"NONINTERESTINCOME", "column_data_type"=>"NUMBER"},
 {"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"VARCHAR"},
 {"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"TIMESTAMP"},
 {"column_name"=>"UPDATEDATE", "column_data_type"=>"TIMESTAMP"}]
expected = [{"column_name"=>"NONINTERESTINCOME", "column_data_type"=>"NUMBER"},
 {"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"NUMBER"},
 {"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"NUMBER"},
 {"column_name"=>"UPDATEDATE", "column_data_type"=>"TIMESTAMP"}]

我需要比较这两个哈希值,找出column_data_type不同的哈希值。

比较我们可以直接使用:

diff = actual -   expected

这会将输出打印为:

{"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"VARCHAR"}
{"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"TIMESTAMP"}

我的预期输出是在结果中我想打印实际和预期的数据类型,表示实际和预期的哈希数组中缺少的`column_name'的数据类型,如:

{"column_name"=>"NONINTERESTEXPENSE", "expected_column_data_type"=>"NUMBER", "actual_column_data_type" => "VARCHAR"}
{"column_name"=>"TRANSACTIONDATE", "expected_column_data_type"=>"NUMBER","actual_column_data_type" => "TIMESTAMP" }

5 个答案:

答案 0 :(得分:1)

无论数组中的哈希顺序如何,这都可以正常工作。

diff = []

expected.each do |elem|
  column_name = elem['column_name']
  column_type = elem['column_data_type']
  match = actual.detect { |elem2| elem2['column_name'] == column_name  }
  if column_type != match['column_data_type']
    diff << { 'column_name' => column_name,
              'expected_column_data_type' => column_type,
              'actual_column_data_type' => match['column_data_type'] }
  end
end

p diff

答案 1 :(得分:1)

[actual, expected].map { |a| a.map(&:dup).map(&:values) }
                  .map(&Hash.method(:[]))
                  .reduce do |actual, expected|
                    actual.merge(expected) do |k, o, n|
                      o == n ? nil : {name: k, actual: o, expected: n}
                    end
                  end.values.compact

#⇒ [
#    [0] {
#            :name => "NONINTERESTEXPENSE",
#          :actual => "VARCHAR",
#        :expected => "NUMBER"
#    },
#    [1] {
#            :name => "TRANSACTIONDATE",
#          :actual => "TIMESTAMP",
#        :expected => "NUMBER"
#    }
# ]

上述方法可轻松扩展以合并N个数组(使用reduce.with_indexmerge使用键"value_from_#{idx}"。)

答案 2 :(得分:0)

这个怎么样?

def select(hashes_array, column_name)
  hashes_array.select { |h| h["column_name"] == column_name }.first
end

diff = (expected - actual).map do |h|
  {
    "column_name" => h["column_name"],
    "expected_column_data_type" => select(expected, h["column_name"])["column_data_type"],
    "actual_column_data_type" => select(actual, h["column_name"])["column_data_type"],
  }
end

PS:肯定这段代码可以改进,看起来更优雅

答案 3 :(得分:0)

(expected - actual).
  concat(actual - expected).
  group_by { |column| column['column_name'] }.
  map do |name, (expected, actual)|
    {
      'column_name'               => name,
      'expected_column_data_type' => expected['column_data_type'],
      'actual_column_data_type'   => actual['column_data_type'],
    }
  end

答案 4 :(得分:0)

<强>代码

def convert(actual, expected)
  hashify(actual-expected, "actual_data_type").
  merge(hashify(expected-actual, "expected_data_type")) { |_,a,e| a.merge(e) }.values
end

def hashify(arr, key)
  arr.each_with_object({}) { |g,h| h[g["column_name"]] =
    { "column_name"=>g["column_name"], key=>g["column_data_type"] } }
end

示例

actual = [
  {"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"TIMESTAMP"},
  {"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"VARCHAR"},
  {"column_name"=>"NONINTERESTINCOME", "column_data_type"=>"NUMBER"},
  {"column_name"=>"UPDATEDATE", "column_data_type"=>"TIMESTAMP"}
]

expected = [
  {"column_name"=>"NONINTERESTINCOME", "column_data_type"=>"NUMBER"},
  {"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"NUMBER"},
  {"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"NUMBER"},
  {"column_name"=>"UPDATEDATE", "column_data_type"=>"TIMESTAMP"}
]

convert(actual, expected)
  #=> [{"column_name"=>"TRANSACTIONDATE",
  #     "actual_data_type"=>"TIMESTAMP", "expected_data_type"=>"NUMBER"},
  #    {"column_name"=>"NONINTERESTEXPENSE",
  #     "actual_data_type"=>"VARCHAR", "expected_data_type"=>"NUMBER"}] 

<强>解释

对于上面的例子,步骤如下。

首先hashify actualexpected

f = actual-expected
  #=> [{"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"TIMESTAMP"},
  #    {"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"VARCHAR"}]

g = hashify(f, "actual_data_type")
  #=> {"TRANSACTIONDATE"=>{"column_name"=>"TRANSACTIONDATE",
  #      "actual_data_type"=>"TIMESTAMP"},
  #    "NONINTERESTEXPENSE"=>{ "column_name"=>"NONINTERESTEXPENSE",
  #      "actual_data_type"=>"VARCHAR"}}

h = expected-actual
  #=> [{"column_name"=>"NONINTERESTEXPENSE", "column_data_type"=>"NUMBER"},
  #    {"column_name"=>"TRANSACTIONDATE", "column_data_type"=>"NUMBER"}]

i = hashify(h, "expected_data_type")
  #=> {"NONINTERESTEXPENSE"=>{"column_name"=>"NONINTERESTEXPENSE",
  #      "expected_data_type"=>"NUMBER"},
  #    "TRANSACTIONDATE"=>{"column_name"=>"TRANSACTIONDATE",
  #      "expected_data_type"=>"NUMBER"}}

下一次合并gi使用Hash#merge的形式,它使用一个块来确定合并的两个哈希中存在的键的值。请参阅doc以了解三个块变量的定义(第一个是公共密钥,我用下划线表示,表示它未在块计算中使用)。

j = g.merge(i) { |_,a,e| a.merge(e) }
  #=> {"TRANSACTIONDATE"=>{"column_name"=>"TRANSACTIONDATE",
  #      "actual_data_type"=>"TIMESTAMP", "expected_data_type"=>"NUMBER"},
  #    "NONINTERESTEXPENSE"=>{"column_name"=>"NONINTERESTEXPENSE",
  #      "actual_data_type"=>"VARCHAR", "expected_data_type"=>"NUMBER"}}

最后,放下钥匙。

k = j.values
  #=> [{"column_name"=>"TRANSACTIONDATE", "actual_data_type"=>"TIMESTAMP",
  #     "expected_data_type"=>"NUMBER"},
  #    {"column_name"=>"NONINTERESTEXPENSE", "actual_data_type"=>"VARCHAR",
  #     "expected_data_type"=>"NUMBER"}]