How to Test Order-Conscious Equality of Hashes

How to test order-conscious equality of hashes

Probably the easiest is to compare the corresponding arrays.

h1.to_a == h2.to_a

Ruby Compare 2 hashes

Two hashes with the same key/value pairs will be equal regardless of key order:

a = {:x => 1, :y => 2}
b = {:y => 2, :x => 1}

a == b
# => true

Testing method that needs to sort hash by value in RSpec

That's because the hashes are the same, see this post. Hashes don't really have a concept of order, when you call the sort_by method it is converting the data to an array, ordering the array, and then returning an array. If you are converting the array to a hash you will lose the order essentially.

If you care about the order here, remove the to_h and just deal with the data as an array instead. Then your tests should work.

You can use .to_a in the test, and you don't need reverse in the sort.

view_counter.sort_by { |route, length| -length }

let(:result) do
{
"/help_page/1" => 3,
"/about/2" => 1,
"/contact" => 1,
"/home" => 1,
"/index" => 2,
}.to_a
end

Is it recommended to use hashcode to determine equality in Java?

This is a terrible way to check for equality, mostly since Objects don't have to be equal to return the same hashcode.

You should always use the equals method for this.

The general rule is:

If the equals method returns true for Objects a and b, the hashCode
method must return the same value for a and b.

This does not mean, that if the hashCode method for a and b returns
the same value, the equals method has to return true for these two
instances.

for instance:

public int hashCode(){
return 5;
}

is a valid, though be it inefficiënt, hashcode implementation.

EDIT:

to use it within an equals method would be something like this:

public class Person{

private String name;

public Person(String name){ this.name = name;}

public String getName(){ return this.name;}

@Override
public boolean equals(Object o){
if ( !(o instanceof Person)){ return false;}
Person p = (Person)o;
boolean nameE = this.name == null ? p.getName() == null : this.name.equals(p.getName());
boolean hashE = nameE ? true : randomTrueOrFalse();
// the only moment you're sure hashE is true, is if the previous check returns true.
// in any other case, it doesn't matter whether they are equal or not, since the nameCheck returns false, so in best case, it's redundant
return nameE && hashE;
}

@Override
public int hashCode(){
int hash = generateValidHashCode();
return hash;
}

}

Testing string equality using hashCode()

because: hashCodes of two objects must be equal if the objects are equal, however, if two objects are unequal, the hashCode can still be equal.

(modified after comment)

How to test if two collections of objects are in a different order based on one of the objects' properties?

To determine if the cards are in the same order by using the Id property, you can simply select that property into an IEnumerable and then use the System.Linq extension method SequenceEqual on them:

// Where 'unshuffled' and 'shuffled' are both 'List<Card>' objects
var areEqual = unshuffled.Select(c => c.Id).SequenceEqual(shuffled.Select(c => c.Id));

Alternatively, you could overried Equals and GetHashCode on the Card class, and then use that for the equality comparison. This will help with other card comparisons that may be needed:

public class Card : IEquatable<Card>
{
public int Id { get; set; }

public bool Equals(Card other)
{
return Id == other?.Id;
}

public override bool Equals(object obj)
{
return Equals(obj as Card);
}

public override int GetHashCode()
{
return Id;
}
}

Now our comparison code is slightly more simple:

var areEqual = unshuffled.SequenceEqual(shuffled);

Is checking hashCode() equality a valid approach to implement equals(Object obj)?

If, as the question says, your hashCode implementation really does guarantee that unequal objects have unequal hash codes, then in principle there is nothing wrong with what you are doing. Your equals method is checking a property that is equivalent to equality, so the behavior is as intended. You should re-check that guarantee, though; remember that no matter how clever you are, you can only store 32 bits of information in an int, which means that most non-trivial objects will necessarily have hash colisions.

However, there are a few caveats. First is clarity: if you implement equals this way, anyone using your code has to look at your hashCode implementation to find out what properties determine equality. Second is speed: if your hash code implementation is significantly slower than simply checking equality of the relevant properties (including boolean shortcutting in that calculation), then it may be worth re-implementing the logic in the equals function to avoid the speed penalty. Third is coupling: implementing equals in this manner means that it depends on that property of hashCode, and any future change to hashCode has to either preserve that property or move the logic into equals.

Compare two hashes no matter symbols or strings, rails

How about this?

require 'set'

def sorta_equal?(sym_hash, str_hash)
return false unless sym_hash.size == str_hash.size
sym_hash.to_a.to_set == str_hash.map { |pair|
pair.map { |o| o.is_a?(String) ? o.to_sym : o } }.to_set
end

sym_hash= {:id=>58, :locale=>:"en-US"}

sorta_equal?(sym_hash, {"id"=>58, "locale"=>"en-US"}) #=> true
sorta_equal?(sym_hash, {"locale"=>"en-US", "id"=>58 }) #=> true
sorta_equal?(sym_hash, {"id"=>58, "local"=>"en-US", "a"=>"b" }) #=> false
sorta_equal?(sym_hash, {"id"=>58, "lacole"=>"en-US"}) #=> false
sorta_equal?(sym_hash, {"id"=>58, [1,2,3]=>"en-US"}) #=> false
sorta_equal?({}, {}) #=> true

class A; end
a = A.new
sorta_equal?({:id=>a, :local=>:b}, {"id"=>a, "local"=>"b"}) #=> true


Related Topics



Leave a reply



Submit