7

我有两个包含数组的哈希。就我而言,数组元素的顺序并不重要。有没有一种简单的方法来匹配 RSpec2 中的此类哈希?

{ a: [1, 2] }.should == { a: [2, 1] } # how to make it pass?

附言

有一个数组匹配器,它忽略了顺序。

[1, 2].should =~ [2, 1] # Is there a similar matcher for hashes?

解决方案

该解决方案对我有用。最初由 tokland 建议,有修复。

RSpec::Matchers.define :match_hash do |expected|
  match do |actual|
    matches_hash?(expected, actual) 
  end
end

def matches_hash?(expected, actual) 
  matches_array?(expected.keys, actual.keys) &&
    actual.all? { |k, xs| matches_array?(expected[k], xs) }
end   

def matches_array?(expected, actual)
  return expected == actual unless expected.is_a?(Array) && actual.is_a?(Array)
  RSpec::Matchers::BuiltIn::MatchArray.new(expected).matches? actual
end

要使用匹配器:

{a: [1, 2]}.should match_hash({a: [2, 1]})
4

4 回答 4

2

我会写一个自定义匹配器:

RSpec::Matchers.define :have_equal_sets_as_values do |expected|
  match do |actual|
    same_elements?(actual.keys, expected.keys) && 
      actual.all? { |k, xs| same_elements?(xs, expected[k]) }
  end

  def same_elements?(xs, ys)
    RSpec::Matchers::BuiltIn::MatchArray.new(xs).matches?(ys)
  end
end

describe "some test" do
  it { {a: [1, 2]}.should have_equal_sets_as_values({a: [2, 1]}) }  
end

# 1 example, 0 failures
于 2012-07-06T19:31:12.687 回答
2

[Rspec 3]
我最终对散列值(数组)进行了排序,如下所示:

hash1.map! {|key, value| [key, value.sort]}.to_h
hash2.map! {|key, value| [key, value.sort]}.to_h
expect(hash1).to match a_hash_including(hash2)

我敢肯定它不会在相当大的阵列上表现出色......

于 2017-02-01T08:41:41.000 回答
1

== on Hashes 不关心顺序,{1 => 2, 3=>4} == {3=>4, 1=>2}。但是,它将检查值是否相等,当然 [2,1] 不等于 [1,2]。我不认为 ~= 是递归的:[[1,2],[3,4]] 可能与 [[4,3],[2,1]] 不匹配。如果是这样,您只需编写两项检查,一项针对键,一项针对值。看起来像这样:

hash1.keys.should =~ hash2.keys
hash1.values.should =~ hash2.values

但正如我所说,这可能行不通。因此,您可能希望扩展 Hash 类以包含自定义方法,例如:

class Hash
  def match_with_array_values?(other)
    return false unless self.length == other.length
    return false unless self.keys - other.keys == []
    return false unless self.values.flatten-other.values.flatten == []
    return true
  end
end
于 2012-07-06T19:09:41.467 回答
1

如果顺序不重要,您可以使用集合而不是数组:

require 'set'
Set.new([1,2]) == Set.new([2,1])
=> true
于 2012-07-06T19:33:13.760 回答