Multiple arguments for Hash#delete

This may be a Facet:

class Hash
alias_method :delete, :delete

 def delete(*keys, &block)
   if keys.length == 1
     __delete__(keys.first, &block)
   else
     keys.map{|key| __delete__(key, &block) }
   end
 end

end

Probably somewhat slower, but hey, it lets you do this

a, b, c = hsh.delete :a, :b, :c

which fits in nicely with

hsh[:a, :b, :c] = 1, 2, 3

and

a, b, c = hsh[:a, :b, :c]

Cheers,
Daniel

Daniel S. wrote:

   end

and

a, b, c = hsh[:a, :b, :c]

Good deal. I’ll add it. Looks to be a safe override too.

Perhaps this is a good update for future version of Ruby?

T.

Trans wrote:

     keys.map{|key| __delete__(key, &block) }

hsh[:a, :b, :c] = 1, 2, 3

and

a, b, c = hsh[:a, :b, :c]

Good deal. I’ll add it. Looks to be a safe override too.

For once… :slight_smile:

Perhaps this is a good update for future version of Ruby?

I think the updated #[], #[]= and #delete all deserve to be in core. The
only problem I see is performance-wise, although implementing them in C
might help there.

Cheers,
Daniel

[email protected] wrote:

Hi,

At Thu, 17 Aug 2006 04:05:08 +0900,
Daniel S. wrote in [ruby-talk:208833]:

Probably somewhat slower, but hey, it lets you do this

a, b, c = hsh.delete :a, :b, :c

What will be returned from `hsh.delete :a’?

The value of :a

hsh = {:a => 1, :b => 2, :c => 3}
hsh.delete :a, :b #=> [1, 2]
hsh.delete :c #=> 3

that way, you can do this

a = hsh.delete :a
b, c = hsh.delete :b, :c

Cool, right?

Cheers,
Daniel

Daniel S. wrote:

Cool, right?

Ah, Nobu has a good point. It’s beeter to have same kind of output. He
also jogs my memory. Array has #delete_values_at and that’s what we
need for Hash too.

def delete_values_at(*keys, &block)
keys.map{|key| delete(key, &block) }
end

Kind of long name though, maybe #delete_at would suffice?

T.

Hi,

At Thu, 17 Aug 2006 23:40:18 +0900,
Daniel S. wrote in [ruby-talk:208980]:

hsh.delete :c #=> 3
The class of returned value varies according to the number of
arguments?

that way, you can do this

a = hsh.delete :a
b, c = hsh.delete :b, :c

 a = [:b, :c]
 b = hsh.delete(*a)

might be confusing, IMHO.

[email protected] wrote:

hsh = {:a => 1, :b => 2, :c => 3}
hsh.delete :a, :b #=> [1, 2]
hsh.delete :c #=> 3

The class of returned value varies according to the number of
arguments?

Yes. I don’t see that as a big problem though, especially if there’s a
second method that always returns an array:

hsh.delete_at :a #=> [1]
hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some, but I think it’s a very cool feature
that won’t interfere with how #delete is being used at the moment.

The main reason for it becoming a Facet is that Hash#[] and Hash#[]=
also work with multiple arguments.

Cheers,
Daniel

Trans wrote:

The value of :a
Cool, right?

Ah, Nobu has a good point. It’s beeter to have same kind of output. He
also jogs my memory. Array has #delete_values_at and that’s what we
need for Hash too.

def delete_values_at(*keys, &block)
keys.map{|key| delete(key, &block) }
end

Kind of long name though, maybe #delete_at would suffice?

Read my mind… yes, I think there should be added a #delete_at method
in addition to the new #delete.

Cheers,
Daniel

Hi,

At Thu, 17 Aug 2006 04:05:08 +0900,
Daniel S. wrote in [ruby-talk:208833]:

Probably somewhat slower, but hey, it lets you do this

a, b, c = hsh.delete :a, :b, :c

What will be returned from `hsh.delete :a’?

Trans wrote:

Also, it really doesn’t work to redefine delete() as you originally
suggested b/c you’d have to use the delete_values_at to ensure you get
an expected result, otherwise you’re assuming preknowledge of how many
elemets are in the Hash.

What do you mean? It would work fine for the purpose I’ve described. If
you want to be sure you get an array when deleting multiple key-value
pairs, use #delete_values_at, otherwise #delete is just fine. The nifty
thing is that it adjusts its return value according to your need.

If #delete should be altered, why should #[] and #[]= ?

Cheers,
Daniel

Daniel S. wrote:

Read my mind… yes, I think there should be added a #delete_at method
in addition to the new #delete.

Here’ is another place in which the interchangeability between Array
andHash is lacking. Array has delete_at(index), while Hash has
delete(key). These two methods should really have the same name. But
array’s delete() method is delete(value), which Hash has no equivalent.
Maybe matz will be willing to do a little shuffling to improve this for
2.0, but the only choice I have in the mean time is the long winded
delete_values_at().

Also, it really doesn’t work to redefine delete() as you originally
suggested b/c you’d have to use the delete_values_at to ensure you get
an expected result, otherwise you’re assuming preknowledge of how many
elemets are in the Hash.

T.

Daniel S. wrote:

Trans wrote:

Also, it really doesn’t work to redefine delete() as you originally
suggested b/c you’d have to use the delete_values_at to ensure you get
an expected result, otherwise you’re assuming preknowledge of how many
elemets are in the Hash.

What do you mean? It would work fine for the purpose I’ve described. If
you want to be sure you get an array when deleting multiple key-value
pairs, use #delete_values_at, otherwise #delete is just fine. The nifty
thing is that it adjusts its return value according to your need.

Yea, I’m just saying YAGNI b/c in the end you won’t use delete() with
more than one index, you’ll use #delete_values_at b/c of the clear
separation of functionality. But…

If #delete should be altered, why should #[] and #[]= ?

You may have a point. Though it doesn’t matter as much becuase it’s
much less often the anyone depends on the return value of []=. ie. we
just use it to set values. But to be very percise it should probably be
changed to match Array’s. Consider that Array’s []= method does take
multuiple parameters related to slicing. Facets’ deals with that by
allowing it to also take an Array parameter:

a = []
a[[1,2,3]] = :a, :b, :c
a #=> [ :a, :b, :c ]

Hash’s can be made to do the same. What do you think?

T.

Daniel S. wrote:

hsh[:a, :b, :c] = 1, 2, 3
a, b, c = hsh.delete(:a, :b, :c)

Simple and elegant.

Yea, I know what you mean. Believe me I went through the same viewpoint
when working on this for Array. Unfortunately the simplicity and
elegance start to crumble when:

a = hsh.delete(*array)

Which leads to things like:

a = [hsh.delete(*array)].flatten

or

a = hsh.delete(*array)
case a
when Array

else

end

Which means you’ll just opt to use #delete_at anyway.

Actually, I don’t like that solution very much. It doesn’t seem very
elegant.

Yes, but sometime simplicity and elegance have to give way to
practicality. I do hope Matz will take some time to address the
“duckability” between Array and Hash for 2.0, though. That would
certainly go a long way toward simplicity and elegance more than
anything.

T.

Trans wrote:

If #delete should be altered, why should #[] and #[]= ?

You may have a point. Though it doesn’t matter as much becuase it’s
much less often the anyone depends on the return value of []=. ie. we
just use it to set values.

I only added #[]= because, with Facets, you can do this (as you of
course know)

hsh[:a, :b, :c] = 1, 2, 3

which matches nicely with

a, b, c = hsh[:a, :b, :c]

My point is that #delete is also a retrieval method, in the sense that
it returns the value it has removed from the hash. Therefore it is
natural for it to have the same functionality as #[], which in turn
means that we have to alter #delete in Facets.

a, b, c = hsh.delete(:a, :b, :c)

Simple and elegant.

But to be very percise it should probably be
changed to match Array’s. Consider that Array’s []= method does take
multuiple parameters related to slicing. Facets’ deals with that by
allowing it to also take an Array parameter:

a = []
a[[1,2,3]] = :a, :b, :c
a #=> [ :a, :b, :c ]

Hash’s can be made to do the same. What do you think?

Actually, I don’t like that solution very much. It doesn’t seem very
elegant.

Cheers,
Daniel

On Aug 17, 2006, at 9:05 AM, Daniel S. wrote:

hsh.delete_at :a #=> [1]
hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some

Then it probably shouldn’t go into Ruby. Especially if you are
proposing two deletion methods that I have to figure out in order to
get the behavior I want.

My brain is full enough, thanks.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Trans wrote:

a = [hsh.delete(*array)].flatten

Which means you’ll just opt to use #delete_at anyway.

Of course you will. In this case, #delete_at fits perfectly well with
the intended usage. I just don’t see the problem with using #delete_at
in such a case, and #delete in cases where you have a known number of
keys.

I propose Facets have both an altered #delete and a #delete_at
method.

Cheers,
Daniel

Hi,

At Sat, 19 Aug 2006 03:56:56 +0900,
Eric H. wrote in [ruby-talk:209285]:

hsh.delete_at :a #=> [1]
hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some

Then it probably shouldn’t go into Ruby. Especially if you are
proposing two deletion methods that I have to figure out in order to
get the behavior I want.

Possiblly, we have to wait until “true multi-value” is
introduced.

Eric H. wrote:

second method that always returns an array:

hsh.delete_at :a #=> [1]
hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some

Then it probably shouldn’t go into Ruby. Especially if you are
proposing two deletion methods that I have to figure out in order to get
the behavior I want.

Well, I only seriously suggested to add it to Facets.

Cheers,
Daniel