Is there any way to check if 2 linked lists have the same elements regardless of order.
edit question: I have fixed the code and given some more details:
this is the method that compares 2 lists
compare: object2
^ ((mylist asBag) = ((objetc2 getList) asBag)).
the method belongs to the class myClass that has a field : myLList. myList is a linkedList of type element.
I have compiled it in the workspace:
a: = element new id:1.
b:= element new id:2.
c:=element new id:3.
d: = element new id:1.
e:= element new id:2.
f:=element new id:3.
elements1 := myClass new.
elements addFirst:a.
elements addFirst:b.
elements addFirst:c.
elements2 := myClass new.
elements addFirst:d.
elements addFirst:e.
elements addFirst:f.
Transcript show: (elements1 compare:elements2).
so I am getting false.. seems like it checks for equality by reference rather than equality by value..
So I think the correct question to ask would be: how can I compare 2 Bags by value? I have tried the '=='..but it also returned false.
EDIT: The question changed too much - I think it deserves a new question for itself.
The whole problem here is that
(element new id: 1) = (element new id: 1)
is giving youfalse
. Unless it's particular class (or superclasses) redefine it, the=
message is resolved comparing by identity (==
) by default. That's why your code only works with a collection being compared with itself.Test it with, for example, lists of numbers (which have the
=
method redefined to reflect what humans understand by numeric equality), and it will work.You should redefine your
element
's class'=
(andhashCode
) methods for this to work.Smalltalk handles everything by reference: all there exist is an object, which know (reference) other objects.
It would be wrong to say that two lists are equivalent if they are in different order, as the order is part of what a list means. A list without an order is what we call a bag.
The
asBag
message (as all of the otheras<anotherCollectionType>
messages) return a new collection of the named type with all the elements of the receiver. So,#(1 2 3 2)
is anArray
of four elements, and#(1 2 3 2) asBag
is a bag containing those four elements. As it's a Bag, it doesn't have any particular order.When you do
bagA := Bag new.
you are creating a newBag
instance, and reference it withbagA
variable. But then you dobagA := myList asBag
, so you lose the reference to the previous bag - the first assignment doesn't do anything useful in your code, as you don't use that bag.Saying
aBool ifTrue: [^true] ifFalse: [^false]
has exactly the same meaning as saying^aBool
- so we prefer just to say that. And, as you only create those two new bags to compare them, you could simplify your whole method like this:Read it out loud: this object (whatever it is) compares to another list if it's list without considering order is the same than the other list without order.
The name
compareTo:
is kind of weird for returning a boolean (containsSameElements:
would be more descriptive), but you get the point much faster with this code.Just to be precise about your questions:
1) It doesn't work because you're comparing
bag1
andbag2
, but just definedbagA
andbagB
.2) It's not efficient to create those two extra bags just because, and to send the senseless
ifTrue:
message, but other way it's OK. You may implement a better way to compare the lists, but it's way better to rely on the implementation ofasBag
and theBag
's=
message being performant.3) I think you could see the
asBag
source code, but, yes, you can assume it to be something like:And, of course, the
addAll:
method could be:So, yes - it creates a new Bag with all the receiver's elements.