-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Array#uniq considers each element eql? method to check if exists #2809
Array#uniq considers each element eql? method to check if exists #2809
Conversation
Actually Array#uniq is considering only value of elements, so is impossible to reduce instances when applying uniq. Considering `eql?` method, if a object is equal any other object that already exists on array, it's automatically removed.
wat record Element, name : String
array = [Element.new(name: "foo"), Element.new(name: "bar")]
p array.uniq &.class |
Hash, whose keyset is used here to determine the unique elements, already calls That's also the reason for the existence of the So all we need to do is define record Element, name : String do
delegate hash, self.class
def ==(other : self)
true
end
end
array = [Element.new(name: "foo"), Element.new(name: "bar")]
p array.uniq |
Does anyone know why ruby has the |
Probably just so you can have different behavior for hashes, or perhaps there was a time where |
Okay one important difference is: [57] pry(main)> 1.0.eql?(1)
=> false
[58] pry(main)> 1.0 == 1
=> true
[59] pry(main)> 1.eql?(1.0)
=> false
[60] pry(main)> 1 == 1.0
=> true So that makes |
For an alternative perspective, Python goes out of its way to make this work as expected. And our expectations are the opposite. >>> hash(234), hash(234.0), hash(Decimal('234.0'))
(234, 234, 234)
>>> hash(0.5), hash(Fraction(1, 2)), hash(Decimal('0.5'))
(1152921504606846976, 1152921504606846976, 1152921504606846976)
>>> {234: 1, 234.0: 2, Decimal('234.0'): 3}
{234: 3} If two equal objects have a different hash, that's a violation of the definition of hashes. I'm quite disappointed about this in Ruby. But it's not so important in Crystal. |
Yes, I think I like Python's behaviour better. I don't know what's a use case for having a Hash with int and float keys where you want to distinguish them (from a purist from of view I think it does make sense, though). We should probably use Python's hash algorithm too. |
@BlaXpirit mine was a different case, but I think now you got it @jhass thank you for pointing me to a solution; I'm porting a ruby lib to crystal, so I thought would make sense the @asterite I just faced a situation where hash for different instances with same values are the same and need to make the check on "instance values level" I'm pretty satisfied with the outcome here, thank you all |
The motivation for this PR is when you have an array with two elements:
In this case an
array.uniq
will always return two elements, but consider you want to return only on Element no matter the name, how should we proceed?The idea is to implement a
#eql?
method on Element class the computes the hash based on instance information, so we can return unique elements, consider in our case we just want to return the first ElementHow the returned hash
array.uniq
will returnps: I don't believe this is the best implementation, specially because this algorithm is O(n2), I'm justing opening this PR to check if makes sense this addition so I can work on a better solution to this problem.