From: Robert Klemme on 4 Jun 2010 06:51 2010/6/4 Marcin Wolski <wolskint(a)o2.pl>: > Robert Dober wrote: >> On Fri, Jun 4, 2010 at 3:41 AM, Marcin Wolski <wolskint(a)o2.pl> wrote: >> <snip> >>> �def ==(other) >>> �@email == other.email >>> �end >> this seems ok >>> >>> �alias eql? == >>> >>> �def hash >>> � �code = 17 >>> � �code = 37*code + @email.hash >>> end >>> >> Are you sure you want to do this? "equal" objects would overwrite each >> other when used as hash keys. This is normally not a good idea, be >> sure you really want/need this! Absolutely agree! > What would be the other possible solution to this problem? Actually I am not sure what the problem actually is. Does OP want to return all objects which are in both Arrays? Does he want to return all objects which share a particular set of properties? etc. Before we can provide solutions we have to know what problem must be solved. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/
From: Anderson Leite on 4 Jun 2010 18:35 Before > we can provide solutions we have to know what problem must be solved. > > Kind regards > > robert I have a list of objects that came from database and another list of objects extracted from a xml. I need the elements who are in both lists. Then...I thought to compare objects overriding the == method like Marcin Wolski wrote. There is another solution ? -- Posted via http://www.ruby-forum.com/.
From: Robert Klemme on 5 Jun 2010 08:32 On 05.06.2010 00:35, Anderson Leite wrote: > Before >> we can provide solutions we have to know what problem must be solved. > I have a list of objects that came from database and another list of > objects extracted from a xml. I need the elements who are in both lists. > > > Then...I thought to compare objects overriding the == method like Marcin > Wolski wrote. There is another solution ? If all objects you are dealing with implement #eql? and #hash in a way to be suitable for that comparison then using #eql? is the most straightforward approach. If they do not and you want to do the comparison based on other criteria then you need to pick a different solution. For example: in_both = obj_from_db.select do |u1| obj_from_xml.any? do |u2| u1.email == u2.email && u1.age == u2.age end end The larger set should be used for the outer iteration. If both sets are really large then you probably rather want to use a different strategy by speeding up access via a Hash. For that you need a specific Hash key (remember, we had assumed #eql? and #hash cannot be used). That key must implement #eql? and #hash; the easiest way to get such a Key class is to use Struct: Key = Struct.new :email, :age db_index = {} obj_from_db.each do |u1| db_index[Key[u1.email, u1.age]] = u1 end in_both = obj_from_xml.select do |u2| db_index[Key[u2.email, u2.age]] end Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/
From: Robert Dober on 5 Jun 2010 10:41 On Sat, Jun 5, 2010 at 2:35 PM, Robert Klemme <shortcutter(a)googlemail.com> wrote: > On 05.06.2010 00:35, Anderson Leite wrote: >> >> Before >>> >>> we can provide solutions we have to know what problem must be solved. > >> I have a list of objects that came from database and another list of >> objects extracted from a xml. I need the elements who are in both lists. >> >> >> Then...I thought to compare objects overriding the == method like Marcin >> Wolski wrote. There is another solution ? > > If all objects you are dealing with implement #eql? and #hash in a way to be > suitable for that comparison then using #eql? is the most straightforward > approach. Not #eql?, #== please. Cheers R. -- The best way to predict the future is to invent it. -- Alan Kay
From: Rein Henrichs on 5 Jun 2010 14:54
First, let's be clear about the semantics of the various comparison methods: The == operator checks whether two objects are equal (after coercing them to the same type). 1 == 2 # => false 1 == 1.0 # => true #eql? checks if two objects are equal and of the same type. 1.eql? 1.0 # => false 'a'.eql? 'a' # => true #equal? checks if two objects are identical (the same object). 'a'.equal? 'a' # => false :a.equal? :a # => true As a mnemonic, note that their strictness is a function of their length. Now, on to the original question, which (paraphrased) is: "How can I get arrays of custom objects to work as expected with the set intersection operator &?" The Array#& operator, like its siblings, uses the #hash and #eql? methods of the objects it compares. These must be the same for objects you want to be considered equivalent. Armed with this knowledge, let's define those methods on User. For instance: class User # checks if objects are equal def ==(other) @email == other.email end # checks if objects are equal and the same class def eql?(other) self == other && self.class == other.class end # unique hash based on email and class # We add 1 to prevent User.new('').hash == User.hash # NOTE: Users with @email == nil will have the same hash and modify if necessary. def hash @email.hash ^ self.class.hash + end end This will allow: > [User.new('bob(a)example.com')] & [User.new('bob(a)example.com')] => [#<User:0x1016dcdb8 @email="bob(a)example.com">] Which I believe was the original intent. Keep in mind that this will also cause Hash to see them as the same object for keys, which is probably also expected As an aside, I would also like to comment that the following, from one of the responses: def to_s "#@email" end is unnecessarily complex and can be replaced simply with: def to_s end Don't use string interpolation when you don't need it. If you want to ensure that @email is a string, call to_s on it instead. On 2010-06-03 15:29:55 -0700, Anderson Leite said: > > I need to compare two arrays of users, and get and third array just with > the matches. I found the "&" method that work for Fixnuns and String, > but...how to use with objects ? > > > class User > attr_accessor :email > end > > a = User.new > a.email = 'ruby(a)rails.com' > > b = User.new > b.email = 'ruby(a)rails.com' > > array_one = [a] > array_two = [b] > > > array_three = array_one & array_two > > puts array_three # I want the user here > > > > Can you help me ? > thanks Rein Henrichs http://puppetlabs.com http://reinh.com |