[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Quiz #65, Principle of Great Surprise, and Array.delete sledgehammer

Dave Howell

2/4/2006 8:50:00 PM

I thought I was actually going to enter my first RubyQuiz, but I've
spent three times as much time trying to get Ruby to stop surprising me
as I have trying to implement my algorithm, and I've had to abandon my
effort since I don't have the time to spend. Sigh.

Can somebody explain to me how I'm supposed to delete a *single*
element from an array based on equivalence with an object? and get back
said array with said element deleted?

In other words....

ar = [1, 2, 3, 8, 15, 15, 8]

ar.delete_one_element!(15)
=> [1, 2, 3, 8, 15, 8]

ar.delete_one_element!(14)
=> [1, 2, 3, 8, 15, 15, 8]

ar.delete_one_element!(nil)
=> [1, 2, 3, 8, 15, 15, 8]

I did find so many different ways of not doing this....

Too enthusiastic....
ar.delete(15)
=> 15
ar
=> [1, 2, 3, 8, 8]

Right results, wrong output...
ar.slice!(ar.index(15))
=> 15
ar
=> [1, 2, 3, 8, 15, 8]

and also surprised me by not handling 'nil' as I wanted...
ar.slice!(ar.index(13))
TypeError: no implicit conversion from nil to integer
from (irb):8:in `slice!'
from (irb):8


I mean, this seems so, er, obvious! "Please find one instance of this
object in the array, and return to me the array without that object. If
the array doesn't have that object, then just give the array back to
me."

Why isn't that the Ruby Way? What am I missing here?

Help?





20 Answers

Levin Alexander

2/4/2006 9:06:00 PM

0

On 2/4/06, Dave Howell <groups@grandfenwick.net> wrote:> I mean, this seems so, er, obvious! "Please find one instance of this> object in the array, and return to me the array without that object. If> the array doesn't have that object, then just give the array back to> me." class Array def without_one(elem) new = self.dup # make a copy so that the original is not changed new.delete_at(new.index(elem)) new end end [1,2,3,4,4,4,5,5].without_one(4) #=> [1,2,3,4,4,5,5]-Levin

James Gray

2/4/2006 9:09:00 PM

0

On Feb 4, 2006, at 2:50 PM, Dave Howell wrote:

> Can somebody explain to me how I'm supposed to delete a *single*
> element from an array based on equivalence with an object? and get
> back said array with said element deleted?

I was just wanting this method yesterday, and not for the first
time. Is there any good reason we can't have a delete_first() method
for Array?

James Edward Gray II


Ara.T.Howard

2/4/2006 9:10:00 PM

0

Logan Capaldo

2/4/2006 9:11:00 PM

0


On Feb 4, 2006, at 3:50 PM, Dave Howell wrote:

> I thought I was actually going to enter my first RubyQuiz, but I've
> spent three times as much time trying to get Ruby to stop
> surprising me as I have trying to implement my algorithm, and I've
> had to abandon my effort since I don't have the time to spend. Sigh.
>
> Can somebody explain to me how I'm supposed to delete a *single*
> element from an array based on equivalence with an object? and get
> back said array with said element deleted?
>
> In other words....
>
> ar = [1, 2, 3, 8, 15, 15, 8]
>
> ar.delete_one_element!(15)
> => [1, 2, 3, 8, 15, 8]
>
> ar.delete_one_element!(14)
> => [1, 2, 3, 8, 15, 15, 8]
>
> ar.delete_one_element!(nil)
> => [1, 2, 3, 8, 15, 15, 8]
>
> I did find so many different ways of not doing this....
>
> Too enthusiastic....
> ar.delete(15)
> => 15
> ar
> => [1, 2, 3, 8, 8]
>
> Right results, wrong output...
> ar.slice!(ar.index(15))
> => 15
> ar
> => [1, 2, 3, 8, 15, 8]
>
> and also surprised me by not handling 'nil' as I wanted...
> ar.slice!(ar.index(13))
> TypeError: no implicit conversion from nil to integer
> from (irb):8:in `slice!'
> from (irb):8
>
>
> I mean, this seems so, er, obvious! "Please find one instance of
> this object in the array, and return to me the array without that
> object. If the array doesn't have that object, then just give the
> array back to me."
>
> Why isn't that the Ruby Way? What am I missing here?
>
> Help?
>
>
>
>
require 'enumerator'
class Array
def delete_one_element(x = nil)
if block_given?
tester = lambda { |item| yield(item) }
else
tester = lambda { |item| item == x }
end
index_of_element = self.to_enum(:each_index).find { |i|
tester.call(self[i]) }
unless index_of_element.nil?
self.delete_at(index_of_element)
end
self
end
end





Levin Alexander

2/4/2006 9:22:00 PM

0

On 2/4/06, Wilson Bilkovich <wilsonb@gmail.com> wrote:> On 2/4/06, Dave Howell <groups@grandfenwick.net> wrote:>> Someone will probably post a solution that uses inject, though. Heh.class Enumerable def delete_one_of(obj) self.inject([],false) { |(arr, already_deleted), elem| arr << elem unless elem == obj and not already_deleted already_deleted = true if elem == obj [arr, already_deleted] }[0] endend... this is untested-Levin, scnr

Simon Kröger

2/4/2006 9:23:00 PM

0


> Why isn't that the Ruby Way? What am I missing here?
>
> Help?

You obviously know how to code such a method yourself and i can't answer
why for example Array#- doesn't work that way (had to learn that myself).

The shortest solution i came up with is

ar = [1, 2, 3, 8, 15, 15, 8]

p ar.values_at(*(0...ar.size).to_a - [ar.index(15)])
=> [1, 2, 3, 8, 15, 8]

p ar.values_at(*(0...ar.size).to_a - [ar.index(14)])
=> [1, 2, 3, 8, 15, 15, 8]

p ar.values_at(*(0...ar.size).to_a - [ar.index(nil)])
=> [1, 2, 3, 8, 15, 15, 8]

cheers

Simon


Dave Howell

2/4/2006 9:42:00 PM

0


On Feb 4, 2006, at 13:22, Simon Kröger wrote:

>
>> Why isn't that the Ruby Way? What am I missing here?
>> Help?
>
> You obviously know how to code such a method yourself and i can't
> answer why for example Array#- doesn't work that way (had to learn
> that myself).

Well, actually, no, I don't. Here's what I bashed together:

class Array
def delete_single(element)
if index=self.index(element) then
self.slice!(index,1)
self
else
nil
end
end
end

It was originally going to be similar to .delete until I realized that
delete didn't return the array, but rather, everything *but* the
array. And it had an optional "yield." I'm mystified as to how to make
THAT part work, since neither ri nor the Pickaxe book gave me any hint
at all as to how to detect IF a block is present, and yield if it is.
Just using "yield" got me an error since I wasn't using a block in this
case.

And even the above code took me hours to figure out, and I don't really
understand why it works. Well, that's not true, but I don't understand
it well enough to be able to figure out if there's a shorter way to do
it. I got that far by noticing what Pickaxe said about Array.slice!

Equivalent to
def slice!(*args)
result = self[*args]
self[*args] = nil
result
end

which basically whispered to me "you have to return something other
than the result of your deletion...." So I tried a couple things until
something worked. {shrug}

> The shortest solution i came up with is
>
> ar = [1, 2, 3, 8, 15, 15, 8]
>
> p ar.values_at(*(0...ar.size).to_a - [ar.index(15)])
> => [1, 2, 3, 8, 15, 8]
>
> p ar.values_at(*(0...ar.size).to_a - [ar.index(14)])
> => [1, 2, 3, 8, 15, 15, 8]
>
> p ar.values_at(*(0...ar.size).to_a - [ar.index(nil)])
> => [1, 2, 3, 8, 15, 15, 8]

Wow. I don't understand this one at all. The "-" operator also was
massively destructive, removing all duplicates when used. I'm going to
have to look up the * operator (as I recall, it's one of those really
strange-and-clever Ruby things) to see what might be going on here.

Oh! Oh oh oh!

My, that's very clever. Create an array containing the *index values*
of the "real" array. They are, of course, each unique. Array-subtract
the index value for the element you want to remove. Array-subtracting
"nil" has no effect but isn't an error. Then use the remaining index
values to copy those elements out of the original "real" array.

Although I'm still going to have to look up what the * is
accomplishing. :)





Dave Howell

2/4/2006 9:47:00 PM

0


On Feb 4, 2006, at 13:10, Logan Capaldo wrote:

> if block_given?

Aha!

<checks index of Pickaxe>

I see. It's in there, but buried near the end of a section in the
middle of the discussion on blocks.

Time for some more highlighting....



Joel VanderWerf

2/4/2006 9:51:00 PM

0

Dave Howell wrote:
> And it had an optional "yield." I'm mystified as to how to make THAT
> part work, since neither ri nor the Pickaxe book gave me any hint at all
> as to how to detect IF a block is present, and yield if it is. Just
> using "yield" got me an error since I wasn't using a block in this case.

Use Kernel.block_given?, like this:

def one_two_three
if block_given?; yield 1; yield 2; yield 3;
else [1,2,3]
end
end

See the PickAxe, in the chapter on blocks and iterators, page 51.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407


James Gray

2/4/2006 9:57:00 PM

0

On Feb 4, 2006, at 3:49 PM, Dave Howell wrote:

>
> On Feb 4, 2006, at 13:09, James Edward Gray II wrote:
>
>> On Feb 4, 2006, at 2:50 PM, Dave Howell wrote:
>>
>>> Can somebody explain to me how I'm supposed to delete a *single*
>>> element from an array based on equivalence with an object? and
>>> get back said array with said element deleted?
>>
>> I was just wanting this method yesterday, and not for the first
>> time. Is there any good reason we can't have a delete_first()
>> method for Array?
>
> Wouldn't delete_first still ought to return "_obj_ or nil"?

Good point. You are probably right.

James Edward Gray II