Problem with Array#delete - RUBY
This is a discussion on Problem with Array#delete - RUBY ; Hello, I'm baffled by the following problem:
I have an Account class and an external array that keeps them in a list. I'm
trying to delete the account objects one at a time as needed, by:
class Account
def quit
...
-
Problem with Array#delete
Hello, I'm baffled by the following problem:
I have an Account class and an external array that keeps them in a list. I'm
trying to delete the account objects one at a time as needed, by:
class Account
def quit
array_name.delete self
end
end
However, this is deleting every account in the list (array_name == []). I've
verified that the account objects are unique. Just for an example, this is
the equivalent of what's happening:
class Account
def quit arr
arr.delete self
end
end
a1 = Account.new
a2 = Account.new
arr = []
arr << a1
arr << a2
a1.quit arr
arr #=> []
Has anyone else experienced this problem, or know what the likely cause is? I
have other arrays that work in the exact same fashion and work as expected.
Thank you for any help,
Matt
-
Re: Problem with Array#delete
On Aug 18, 2007, at 12:59 AM, Matthew B Gardner wrote:
> Hello, I'm baffled by the following problem:
>
> I have an Account class and an external array that keeps them in a
> list. I'm
> trying to delete the account objects one at a time as needed, by:
>
> class Account
> def quit
> array_name.delete self
> end
> end
>
> However, this is deleting every account in the list (array_name ==
> []). I've
> verified that the account objects are unique. Just for an example,
> this is
> the equivalent of what's happening:
>
> class Account
> def quit arr
> arr.delete self
> end
> end
>
> a1 = Account.new
> a2 = Account.new
> arr = []
> arr << a1
> arr << a2
> a1.quit arr
> arr #=> []
>
> Has anyone else experienced this problem, or know what the likely
> cause is? I
> have other arrays that work in the exact same fashion and work as
> expected.
I ran your code and I didn't have a problem: it did what you
expected. Are you sure that the code you posted is exactly the same
as the code that is giving you trouble?
Regards, Morton
-
Re: Problem with Array#delete
Matthew B Gardner wrote:
> Hello, I'm baffled by the following problem:
>
> I have an Account class and an external array that keeps them in a list. I'm
> trying to delete the account objects one at a time as needed, by:
>
> class Account
> def quit
> array_name.delete self
> end
> end
>
> However, this is deleting every account in the list (array_name == []). I've
> verified that the account objects are unique. Just for an example, this is
> the equivalent of what's happening:
>
> class Account
> def quit arr
> arr.delete self
> end
> end
>
> a1 = Account.new
> a2 = Account.new
> arr = []
> arr << a1
> arr << a2
> a1.quit arr
> arr #=> []
>
>
> Has anyone else experienced this problem, or know what the likely cause is? I
> have other arrays that work in the exact same fashion and work as expected.
>
> Thank you for any help,
> Matt
>
>
Wow, that was a well-asked question. This seems like a Ruby bug, though
I can't reproduce it. When I run the code you posted, arr[] still
contains a2 (as it should). I am using Ruby 1.8.6 (on Linux). What are
you using?
Dan
-
Re: Problem with Array#delete
Sorry, I only meant the code I posted as an example of what is happening --
the actual code would be a little hard to gather and format, but I will do so
if the following isn't enough information:
ruby -v #=> ruby 1.8.4 (2005-12-24) [i486-linux]
Ok, I threw this code in to gather some info, and following it is the
printout:
p world.characters.class
p world.characters.size
world.characters.each do |ch|
p ch.class
p ch.object_id
end
world.characters.delete(self)
p world.characters
Array
2
Character
-607336504
Character
-607410834
[]
Do I need to format up the code, or is there something telling from the
information here?
Thanks,
Matt
On Saturday 18 August 2007 02:17, Morton Goldberg wrote:
> On Aug 18, 2007, at 12:59 AM, Matthew B Gardner wrote:
> > Hello, I'm baffled by the following problem:
> >
> > I have an Account class and an external array that keeps them in a
> > list. I'm
> > trying to delete the account objects one at a time as needed, by:
> >
> > class Account
> > def quit
> > array_name.delete self
> > end
> > end
> >
> > However, this is deleting every account in the list (array_name ==
> > []). I've
> > verified that the account objects are unique. Just for an example,
> > this is
> > the equivalent of what's happening:
> >
> > class Account
> > def quit arr
> > arr.delete self
> > end
> > end
> >
> > a1 = Account.new
> > a2 = Account.new
> > arr = []
> > arr << a1
> > arr << a2
> > a1.quit arr
> > arr #=> []
> >
> > Has anyone else experienced this problem, or know what the likely
> > cause is? I
> > have other arrays that work in the exact same fashion and work as
> > expected.
>
> I ran your code and I didn't have a problem: it did what you
> expected. Are you sure that the code you posted is exactly the same
> as the code that is giving you trouble?
>
> Regards, Morton
-
Re: Problem with Array#delete
On 18.08.2007 08:34, Matthew B Gardner wrote:
> Sorry, I only meant the code I posted as an example of what is happening --
> the actual code would be a little hard to gather and format, but I will do so
> if the following isn't enough information:
>
> ruby -v #=> ruby 1.8.4 (2005-12-24) [i486-linux]
>
> Ok, I threw this code in to gather some info, and following it is the
> printout:
>
> p world.characters.class
> p world.characters.size
> world.characters.each do |ch|
> p ch.class
> p ch.object_id
> end
> world.characters.delete(self)
> p world.characters
>
> Array
> 2
> Character
> -607336504
> Character
> -607410834
> []
>
> Do I need to format up the code, or is there something telling from the
> information here?
The crucial bit is missing: how did you define ==, eql? and hash in your
class? Did you define them? If not, using Struct might help because
that gives you those methods for free:
YourClass = Struct.new :name,
ther_field do
def method_you_need
end
end
Then eql?, == and hash will be implemented in terms of "name" and
"other_field".
Kind regards
robert
-
Re: Problem with Array#delete
I went a little different route, but that was indeed the problem. I just
defined == in my class, which I guess was comparing the class of the object
instead of the object_id. I did:
def == obj
self.equal?(obj)
end
If you have time, or if someone else does, is there a quick explanation of why
this happened in this instance, but not with similar classes that function
fine with essentially duplicate methods of adding to and deleting from
arrays? Hopefully I can avoid future problems if I understand what's
happening (I'm a hobby programmer, so I lack some technical expertise).
Thank you, and the other repliers, for the help -- it's very much appreciated.
-Matt
On Saturday 18 August 2007 05:09, Robert Klemme wrote:
> On 18.08.2007 08:34, Matthew B Gardner wrote:
> > Sorry, I only meant the code I posted as an example of what is happening
> > -- the actual code would be a little hard to gather and format, but I
> > will do so if the following isn't enough information:
> >
> > ruby -v #=> ruby 1.8.4 (2005-12-24) [i486-linux]
> >
> > Ok, I threw this code in to gather some info, and following it is the
> > printout:
> >
> > p world.characters.class
> > p world.characters.size
> > world.characters.each do |ch|
> > p ch.class
> > p ch.object_id
> > end
> > world.characters.delete(self)
> > p world.characters
> >
> > Array
> > 2
> > Character
> > -607336504
> > Character
> > -607410834
> > []
> >
> > Do I need to format up the code, or is there something telling from the
> > information here?
>
> The crucial bit is missing: how did you define ==, eql? and hash in your
> class? Did you define them? If not, using Struct might help because
> that gives you those methods for free:
>
> YourClass = Struct.new :name,
ther_field do
> def method_you_need
> end
> end
>
> Then eql?, == and hash will be implemented in terms of "name" and
> "other_field".
>
> Kind regards
>
> robert
-
Re: Problem with Array#delete
On 18.08.2007 11:44, Matthew B Gardner wrote:
> I went a little different route, but that was indeed the problem. I just
> defined == in my class, which I guess was comparing the class of the object
> instead of the object_id. I did:
>
> def == obj
> self.equal?(obj)
> end
>
> If you have time, or if someone else does, is there a quick explanation of why
> this happened in this instance,
If you just defined == the way you presented above then the issue should
not have occurred because equal? tests for identity. It's difficult to
comment on fragments when the whole code is not presented.
> but not with similar classes that function
> fine with essentially duplicate methods of adding to and deleting from
> arrays?
I am not sure what you mean by this. Can you elaborate?
> Hopefully I can avoid future problems if I understand what's
> happening (I'm a hobby programmer, so I lack some technical expertise).
There are some concepts you should keep in mind that have some
similarities and will typically wreck havoc on your code when confused.
Both define relations (in the mathematical sense) on objects.
First, there is "identity". Two objects are identical when they are
actually just one, i.e. the same instance.
Then, there is equivalence. Equivalence is defined per class. For
example two strings containing the same sequence of characters are
equivalent. Sometimes only identical instances are equivalent.
Now, these different concepts are implemented in Ruby via different methods:
eql? and == implement equivalence
equal? implements identity
Most containers (an Array is a container) use equivalence, namely
implemented via eql? to test whether some objects match (e.g. for
deletion), because it is the more flexible and more useful concept.
(Think of an Array of Strings and you want to delete one of them with a
certain character sequence, you would want to provide a string with that
sequence as template and not the exact same object in the array - which
you might not know beforehand.)
Now, there is a slight twist: since for some algorithms it's not
efficient to compare something against all elements in the container
(for example, Array#uniq would have to compare every element of the
array with every other element which is O(n*n), i.e. if you double the
elements in the Array you quadruple the number of comparisons
necessary). In those cases (unfortunately they are not all documented)
typically a Hash is used behind the scenes. For objects to work
properly as Hash key methods eql? *and* hash need to be implemented
properly.
Consequence is, that you should always implement eql? and hash (and also
== for consistency) reasons *if* you plan to use instances of your class
in these circumstances *and* want to define equivalence different than
via identity (which happens to be the default implementation in class
Object). Typically you will choose some fields for this and you must
also make sure that equivalent instances yield the same (!) hash code.
Normally you do that by applying some math operation (binary XOR is
frequently used, because it's fast and guarantees that all values used
influence the result) on the hash values of those members that you
determine as key elements for equivalence.
The easiest way to do that is by using Struct, because that will
generate a class with all the necessary methods. Example:
# name and age are key for Foo
Foo = Struct.new :name, :age do
attr_accessor :unimportant_other_attribute
end
irb(main):007:0> f1 = Foo.new("a", 10)
=> #<struct Foo name="a", age=10>
irb(main):008:0> f2 = Foo.new("a", 10)
=> #<struct Foo name="a", age=10>
irb(main):009:0> f1.hash
=> -2186440
irb(main):010:0> f2.hash
=> -2186440
irb(main):011:0> f1.eql? f2
=> true
irb(main):012:0> f1 == f2
=> true
irb(main):013:0> f1.equal? f2
=> false
irb(main):014:0> f1.unimportant_other_attribute = "bar"
=> "bar"
irb(main):015:0> f1.eql? f2
=> true
irb(main):016:0> f1.name = "hello"
=> "hello"
irb(main):017:0> f1.eql? f2
=> false
There is another thing you should be aware: numbers in Ruby actually
implement *two* different equivalence relations:
irb(main):018:0> 1 == 1.0
=> true
irb(main):019:0> 1.eql? 1.0
=> false
irb(main):020:0> 1.hash
=> 3
irb(main):021:0> 1.0.hash
=> 233071
But most classes treat == and eql? synonym.
Next week we'll dive into ordering and operator <=>. :-))
Kind regards
robert
-
Re: Problem with Array#delete
> I went a little different route, but that was indeed the problem. I just=
=20
> defined =3D=3D in my class, which I guess was comparing the class of the =
object=20
> instead of the object_id. I did:
>=20
> def =3D=3D obj
> =A0=A0=A0=A0=A0=A0self.equal?(obj)
> end
Ok, so it looks like this didn't work so well after all. Initially, I thoug=
ht=20
it did because I reloaded the character.rb file while the program was runni=
ng=20
and it worked fine. However, when I shutdown the program and started it bac=
k=20
up, I experienced the same problem (though it again worked after reloading=
=20
the file). I'll post all the necessary code:
def world
returns the world object
end
class World
def initialize
characters =3D []
end
end
class Account
def foo
@character =3D Character.new()
world.characters << @character
end
end
class Character
def quit
p self.object_id
p world.characters.class
p world.characters.size
world.characters.each do |ch|
p ch.class
p ch.object_id
end
world.characters.delete(self)
p world.characters
end
end
This is the output from Character#quit, with two character objects in the=20
world#characters array:
=2D607170236
Array
2
Character
=2D607170236
Character
=2D607240286
[]
As you can see, both Character objects are being deleted when only the firs=
t=20
should be (at least as far as my intention). In an attempt to fix this, I=20
added the following method:
class Character
def =3D=3D obj
self.equal?(obj)
end
end
I thought this did fix it, because I reloaded the file and tested it -- and=
it=20
only deleted the targeted object. However, when I restarted the program, it=
=20
didn't work and deleted both objects again. Without changing anything, and=
=20
just reloading the file while the program was still running, it worked as=20
intended again and deleted only the targeted object.
I have an Account class that utilizes World#accounts (an Array object) in t=
he=20
exact same way that Character utilizes World#characters, and the deletion o=
f=20
accounts works fine.
Robert, thank you for your reply -- I hope that this answers the noted=20
questions that you had, and maybe even provides some more insight into what=
=20
the problem might be. Is there an explanation for why the Character#=3D=3D =
method=20
works after being reloaded, but not at start time? Also, Robert, I reviewed=
=20
the portion of your reply regarding a Struct object, and it doesn't look li=
ke=20
it would be beneficial in my case -- I'm just trying to add and delete sing=
le=20
instances of a class from an array -- but I could be wrong?
Thanks again for any help,
Matt
-
Re: Problem with Array#delete
--1926193751-2036615464-1187462143=:4504
Content-Type: MULTIPART/MIXED; BOUNDARY="1926193751-2036615464-1187462143=:4504"
This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.
--1926193751-2036615464-1187462143=:4504
Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE
Hi --
On Sun, 19 Aug 2007, Matthew B Gardner wrote:
>> I went a little different route, but that was indeed the problem. I just
>> defined =3D=3D in my class, which I guess was comparing the class of the=
object
>> instead of the object_id. I did:
>>
>> def =3D=3D obj
>> =A0=A0=A0=A0=A0=A0self.equal?(obj)
>> end
>
> Ok, so it looks like this didn't work so well after all. Initially, I tho=
ught
> it did because I reloaded the character.rb file while the program was run=
ning
> and it worked fine. However, when I shutdown the program and started it b=
ack
> up, I experienced the same problem (though it again worked after reloadin=
g
> the file). I'll post all the necessary code:
>
> def world
> =09returns the world object
> end
>
> class World
> =09def initialize
> =09=09characters =3D []
> =09end
> end
Can you un-pseudo-code the code to the point where it does (or doesn't
do) what you want? I can't make the thing you're describing happen
when I try to get the code up and running, so a complete (non-)working
example would be good.
David
--=20
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
--1926193751-2036615464-1187462143=:4504--
--1926193751-2036615464-1187462143=:4504--
-
Re: Problem with Array#delete
Thank you to everyone who has tried to help me with this today -- I know for
certain -what- the problem is now, after adding in some testing. My Character
class, for whatever reason, is using == to evaluate class. So, when I am
trying to use Array#delete (array.delete(self) for a Character object), it's
deleting every Character object in that array instead of just that single
instance. I've tried to fix this issue by defining the == method in my
Character class like this:
def Character
def == obj
self.equal?(obj)
end
end
However, this doesn't initially work -- I have to reload the file during
runtime for it to utilize the above method. For sake of clarity, this is what
I mean:
Start program...
a = Character.new
b = Character.new
a == b #=> true
Reload character.rb file while program is running...
a == b #=> false
Hopefully that gets my meaning across. I'm not sure why Character#== isn't
initially getting used, or if there's something wrong with my declaration.
I'm also not sure why Character#== (prior to my defining Character#==) is
comparing class and my other classes aren't.
I hope that this description is satisfactory -- and thank you for any help
that can be offered.
-Matt
On Saturday 18 August 2007 14:35, David A. Black wrote:
Similar Threads
-
By Application Development in forum RUBY
Replies: 4
Last Post: 11-09-2007, 05:47 AM
-
By Application Development in forum RUBY
Replies: 20
Last Post: 11-08-2007, 09:09 AM
-
By Application Development in forum c++
Replies: 18
Last Post: 10-10-2007, 05:59 AM
-
By Application Development in forum c++
Replies: 3
Last Post: 08-17-2007, 02:15 AM
-
By Application Development in forum REXX
Replies: 2
Last Post: 11-10-2006, 01:55 PM