Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何比较散列中的许多值_Ruby - Fatal编程技术网

Ruby 如何比较散列中的许多值

Ruby 如何比较散列中的许多值,ruby,Ruby,我有一个散列,看起来像下面的一个。我想将所有“之前”值与其对应的“之后”值进行比较。当所有代码都相同时,我执行一些代码。。目前我用IF语句来做,这很难看。我通常怎么做 hash = { "id_BEFORE"=>10825, "name_BEFORE"=>"management", "prefix_BEFORE"=>"10.70.230.0/24", "created_at_BEFORE"=>Thu, 10 Oct 2019 12:07:23 UTC +

我有一个散列,看起来像下面的一个。我想将所有“之前”值与其对应的“之后”值进行比较。当所有代码都相同时,我执行一些代码。。目前我用IF语句来做,这很难看。我通常怎么做

 hash = {
  "id_BEFORE"=>10825,
  "name_BEFORE"=>"management",
  "prefix_BEFORE"=>"10.70.230.0/24",
  "created_at_BEFORE"=>Thu, 10 Oct 2019 12:07:23 UTC +00:00,
  "updated_at_BEFORE"=>Thu, 10 Oct 2019 12:07:23 UTC +00:00,
  "snapshot_id_BEFORE"=>18,
  :entry1_ipnexthop_BEFORE=>"10.70.230.72",
  :entry1_ifname_BEFORE=>"mgmt0",
  :entry1_pref_BEFORE=>0,
  :entry1_metric_BEFORE=>0,
  :entry1_clientname_BEFORE=>"direct",
  :entry1_route_type_BEFORE=>"",
  "id_AFTER"=>10828,
  "name_AFTER"=>"management",
  "prefix_AFTER"=>"10.70.230.0/24",
  "created_at_AFTER"=>Thu, 10 Oct 2019 12:07:35 UTC +00:00,
  "updated_at_AFTER"=>Thu, 10 Oct 2019 12:07:35 UTC +00:00,
  "snapshot_id_AFTER"=>19,
  :entry1_ipnexthop_AFTER=>"10.70.230.72",
  :entry1_ifname_AFTER=>"mgmt0",
  :entry1_pref_AFTER=>0,
  :entry1_metric_AFTER=>0,
  :entry1_clientname_AFTER=>"direct",
  :entry1_route_type_AFTER=>""
 }

如果你把所有的键都做成字符串,你可以做如下的事情

hash.select { |k, _v| k.end_with?("BEFORE") }.all? { |k, v| v == hash["#{k.gsub("_BEFORE", "")}_AFTER"] }
试着这样做:

diff = hash.select do |k, v|
  next unless k.to_s.include?('AFTER')

  attr = k.to_s.split('AFTER').first
  v != (hash["#{attr}BEFORE"] || hash["#{attr}BEFORE".to_sym])
end

p diff
#=> { "id_AFTER" => 10828, "created_at_AFTER" => "Thu, 10 Oct 2019 12:07:35 UTC +00:00","updated_at_AFTER" => "Thu, 10 Oct 2019 12:07:35 UTC +00:00", "snapshot_id_AFTER" => 19 }

# You can use it in IF statement
do_something if diff.empty?
代码

def pairs?(h, suffix1, suffix2)
  h1 = select(h, suffix1).transform_keys do |k|
    case k
    when Symbol
      k.to_s.sub(/#{suffix1}\z/, suffix2).to_sym
    else # String
      k.sub(/#{suffix1}\z/, suffix2)
    end
  end
  h2 = select(h, suffix2)
  h1.all? { |k,v| h2[k] == v }
end

def select(h, suffix)
  h.select { |k,_| k.to_s.end_with?(suffix) }
end
示例

h = {
  "id_BEFORE"=>10825,
  "id_AFTER" =>10828,
  :entry1_ipnexthop_BEFORE => "10.70.230.72",
  :entry1_ipnexthop_AFTER  => "10.70.230.72",
  "name_BEFORE"            => "management",
  "name_AFTER"             => "management",
  "prefix_BEFORE"          => "10.70.230.0/24",
  "prefix_AFTER"           => "10.70.230.0/24",
  "1_more_AFTER"           => "fake value" 
}

解释

注意,(不像)返回一个散列

对于示例中定义的
h
,步骤如下所示

suffix1 = "_BEFORE"
suffix2 = "_AFTER"

g = select(h, suffix1)
  #=> {"id_BEFORE"=>10825, :entry1_ipnexthop_BEFORE=>"10.70.230.72",
  #    "name_BEFORE"=>"management", "prefix_BEFORE"=>"10.70.230.0/24"} 
h1 = g.transform_keys do |k|
  case k
  when Symbol
    k.to_s.sub(/#{suffix1}\z/, suffix2).to_sym
  else # String
    k.sub(/#{suffix1}\z/, suffix2)
  end
end
  #=> {"id_AFTER"=>10825, :entry1_ipnexthop_AFTER=>"10.70.230.72",
  #    "name_AFTER"=>"management", "prefix_AFTER"=>"10.70.230.0/24"} 
h2 = select(h, suffix2)
  #=> {"id_AFTER"=>10828, :entry1_ipnexthop_AFTER=>"10.70.230.72",
  #    "name_AFTER"=>"management", "prefix_AFTER"=>"10.70.230.0/24",
  #     "1_more_AFTER"=>"fake value"} 
h1.all? { |k,v| h2[k] == v }
  #=> false
返回
false
,因为
h2[k]==v#=>false
k#=>id_在
之后(所以
h2[k]=>10828
)和
v#=>10825

如果我们将
h[“id_AFTER”]
的值更改为
10825
,则返回
true

h2 = select(h.merge("id_AFTER"=>10825), suffix2)
  #=> {"id_AFTER"=>10825, :entry1_ipnexthop_AFTER=>"10.70.230.72",
  #    "name_AFTER"=>"management", "prefix_AFTER"=>"10.70.230.0/24",
  #    "1_more_AFTER"=>"fake value"} 
h1.all? { |k,v| h2[k] == v }
  #=> true     h1.all? { |k,v| h2[k] == v }

这将比较键包含字符串“BEFORE”的所有值与键包含字符串“AFTER”的所有值,如果值相同,则返回
true
,如果值不相同,则返回
false

h.select { |k, _| k =~ /BEFORE/ }.values == h.select { |k, _| k =~ /AFTER/ }.values
我想这就是你要找的?如果不能保证值的顺序相同,你就必须做一些额外的事情。如果值的顺序不一致,那么首先将它们全部映射到字符串,然后对它们进行排序。(如果你不将它们全部映射到字符串,如果你试图用
#sort
将整数与字符串进行比较,你就会遇到麻烦。)例如:
h.select{k,{k=~/BEFORE/}.values.map(&:to.s).sort

要将其插入代码中,请执行以下操作:

if h.select { |k, _| k =~ /BEFORE/ }.values == h.select { |k, _| k =~ /AFTER/ }.values
  # Execute the code you want to execute
end
您还可以将其分解为方法。这样读起来可能更容易:

def values_are_equal(h)
  h.select { |k, _| k =~ /BEFORE/ }.values == h.select { |k, _| k =~ /AFTER/ }.values
end

def execute_some_code
  # execute your code
end

execute_some_code if values_are_equal(h)
编辑:正如Cary所解释的,如果两个键的值被转置,这将不起作用。例如,如果您的哈希包含这些值:

:entry1_pref_BEFORE=>1
:entry1_metric_BEFORE=>0    
:entry1_pref_AFTER=>0
:entry1_metric_AFTER=>1

它们在
BEFORE
BEFORE
键中的值是相同的。如果发生这种情况,你不能使用我描述的方法,你可以使用Cary的方法。

很好的答案。起初我认为
hash={“id_BEFORE”=>10828,“id_BEFORE”=>10828,“cat_AFTER=“meow”}
会是个问题,但问题并不要求“键之后的所有
”的值等于“
键之前的所有
”的值。请注意,
true
false
的返回值是所有要求的(
diff.empty?
,但是使用
hash.any?
hash.all?
更直接。我刚刚注意到一个问题。假设
hash={“a_BEFORE”=>“cat”,:a_AFTER=>“cat”}
,然后
diff=>
.Cary,你为什么不能将包含“BEFORE”的键与包含“AFTER”的键进行匹配,看看这两个子集是否相等?我是否遗漏了什么?@BobRodes,OP声明,“我想将所有“BEFORE”值与其对应的“AFTER”值进行比较。”我假设,对于名称以“
之前的“\u”结尾的每个键
kb
,都有一个键
ka
,除了在“之后以“
”结尾外,其他键都有相同的名称,
h[ka]==h[kb]\=>true
。另外,请注意,在我的示例中,没有键
在“
之前多1个”来匹配键
“之后多1个”
。我这样做是为了说明问题并不排除“
键之后可能有
”而之前没有相应的
”的可能性
键。好吧,但我还是不明白你为什么要这么麻烦。我并不想批评你,因为我可能遗漏了什么。但是,为什么你不能简单地选择所有正则表达式与
/BEFORE/
匹配的键,抓取值,然后对所有匹配
/BEFORE/
的键执行相同的操作,然后比较结果假设
h={'a_在'=>1'之前,b_在'=>2'之前,b_在'=>1'之后,b_在'=>1'之后,a_在'=>2'之后。
假设
h={'a_在'=>1'之前,a_在'=>2'之后,两组值是否相等值,但它们的值的数组都是
[1,2]
(按键顺序)。再举一个例子,假设
h={'a_在'=>1'之前,'a_在'=>1'之后,'b_在'=>2}
。所有的“BEFORE”值(只有一个)都等于它们相应的“AFTER”值,但它们的值的数组不:
[1]
对于BEFORE,
[1,2]
对于AFTER…,如果你比较一组值,而不是一组值,你会遇到与我给出的示例相同的问题。如果你有,比如说,
{a_BEFORE'=>1,:a_BEFORE=>2,'b_BEFORE'=>2,:b_AFTER=>1},那么“…首先将它们全部映射到字符串…”可能是个问题
@CarySwoveland是的,如果出现问题,那将是一个问题。在某些问题域中,你肯定必须考虑到它。但是“下面的哈希”没有问题。我想问题是,是吗?也许一个健壮的解决方案必须解决这种可能性。
def values_are_equal(h)
  h.select { |k, _| k =~ /BEFORE/ }.values == h.select { |k, _| k =~ /AFTER/ }.values
end

def execute_some_code
  # execute your code
end

execute_some_code if values_are_equal(h)
:entry1_pref_BEFORE=>1
:entry1_metric_BEFORE=>0    
:entry1_pref_AFTER=>0
:entry1_metric_AFTER=>1