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
Ruby Sequel: Array Returned by Query Is Being Returned as a String Object, Not an Array Object
Pass Arguments by Reference to a Block with the Splat Operator
Jekyll:New Posts Not Being Generated
Rewrite Template.Js.Erb into Template.Js.Slim
Error When Starting Sinatra: "Tried to Create Proc Object Without a Block"
Determining Method's Visibility on the Fly
Ruby's "Foo = True If !Defined? Foo" Won't Work as Expected
Getting Hash with Symbol as Keys for Mongo in Rails
Recursively Convert Hash Containing Non-Utf Chars to Utf
Uml Sequence Diagram - How to Represent Method Arguments That Instantiate Objects
Working with Multiple Processes in Ruby
How to Collapse Double Splat Arguments into Nothing
Gem::Ext::Builderror: Error: Failed to Build Gem Native Extension. on Cenos 6.5
Openssl Causing Very Slow Rails Boot Time on Windows
Why Are Parenthesis Sometimes Required in Ruby
Can Nokogiri Use Single Quotes for Attributes on Saving Xml
How to Stop Bundler from Adding Ruby Version to Gemfile.Lock