Behaviour of Enumerables reject vs. select mixed into Hash


A

Alexander Presber

Hello everybody,

Could you please take a look at the result of the following statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash (instead of
an array of key-value pairs)?

Thanks for any comments
Sincerely yours
Alexander Presber
 
Ad

Advertisements

T

Trans

Hello everybody,

Could you please take a look at the result of the following statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash (instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.

T.
 
R

Robert Dober

Hello everybody,

Could you please take a look at the result of the following statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash (instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.

So do I, Do you happen to have some remedies for this in Facets?
I am trying to unify such things in my library, but I am not building
something even close to Factes[1], however if you are interested in
some peaces let me know.

Cheers
Robert

[1] because than I would just use Facets which is really great, but I
want a small library and I want magic dot notation, which are liked by
few only :(

R.
 
A

Alexander Presber

Hello everybody,
Could you please take a look at the result of the following
statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash (instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.

Absolutely.
But the most baffling to me is, that it does not even act
_consistently_, see my original examples.
From a logical point of view (or at least the principle of least
surprise), selecting some elements should be identical
to dropping the others.

Is there anybody who can explain, why it had to be implemented that way?
Is there any chance of that getting changed in the future?

Sincerely yours,
Alexander Presber
 
R

Robert Klemme

Hello everybody,

Could you please take a look at the result of the following statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash (instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.

Absolutely.
But the most baffling to me is, that it does not even act
_consistently_, see my original examples.
From a logical point of view (or at least the principle of least
surprise), selecting some elements should be identical
to dropping the others.

Is there anybody who can explain, why it had to be implemented that way?
Is there any chance of that getting changed in the future?

The #select in Enumerable can only return a "general" type - in this
case an Array. Making Enumerable depend on the class is not a good idea
IMHO. Maybe an implementation using #dup would help though...

Of course Hash#select could act differently but that a) might hurt duck
typing and b) could break existing code. Note that you can always do
something like

selected = a_hash.dup.delete_if {|k,v| ... }

Kind regards

robert
 
A

Alexander Presber

Hello everybody,

Could you please take a look at the result of the following
statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the
original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash
(instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.
Absolutely.
But the most baffling to me is, that it does not even act
_consistently_, see my original examples.
From a logical point of view (or at least the principle of least
surprise), selecting some elements should be identical
to dropping the others.
Is there anybody who can explain, why it had to be implemented
that way?
Is there any chance of that getting changed in the future?

The #select in Enumerable can only return a "general" type - in
this case an Array. Making Enumerable depend on the class is not a
good idea IMHO. Maybe an implementation using #dup would help
though...

Of course Hash#select could act differently but that a) might hurt
duck typing and b) could break existing code. Note that you can
always do something like

selected = a_hash.dup.delete_if {|k,v| ... }

Kind regards

robert
 
Ad

Advertisements

A

Alexander Presber

Am 21.06.2007 um 11:20 schrieb Robert Klemme:
Hello everybody,

Could you please take a look at the result of the following
statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the
original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash
(instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.
Absolutely.
But the most baffling to me is, that it does not even act
_consistently_, see my original examples.
From a logical point of view (or at least the principle of least
surprise), selecting some elements should be identical
to dropping the others.
Is there anybody who can explain, why it had to be implemented
that way?
Is there any chance of that getting changed in the future?

Sorry for the empty post, to much clicking without thinking.
The #select in Enumerable can only return a "general" type - in
this case an Array.

I see, but isn't that restating the problem?

Even though "Programming Ruby" states: [snip] Enumerable#reject:
returns an array for all elements of enumObj for which block is false
(see also Enumerable#find_all) [/snip],
reject _respects_ the class it acts upon in returning a _hash_, not
an array.
Not so select.
Do you see the inconsistency?
Making Enumerable depend on the class is not a good idea IMHO.
Maybe an implementation using #dup would help though...

Could you please elaborate into that? I do not understand.
Of course Hash#select could act differently but that a) might hurt
duck typing

I fail to see why, could you give an example?
and b) could break existing code.

That is true.
Note that you can always do something like

selected = a_hash.dup.delete_if {|k,v| ... }

Not quite. hsh.dup.delete_if is equivalent to hsh.reject, and reject
works just fine.
And of course I could always use Hash#reject (or hash#delete_if for
that matter) instead of Hash#select by just negating the block.

But the problem I see lies within the inconsistent return type of
Hash#select.

I could imagine if one wanted to change that behaviour, the "mixee"
class would have to provide certain capabilities to be able to get
Enumerable#select, much like objects have to provide an
implementation of said:
Kind regards

robert

Yours truly,
Alexander
 
D

dblack

Hi --

Am 21.06.2007 um 11:20 schrieb Robert Klemme:
Hello everybody,

Could you please take a look at the result of the following statements:

irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}

irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}

irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]

The result of the reject statement is clearly sensible: the original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash (instead of
an array of key-value pairs)?

I have to concur. I've never liked that. You'd think there'd be some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.
Absolutely.
But the most baffling to me is, that it does not even act _consistently_,
see my original examples.
From a logical point of view (or at least the principle of least
surprise), selecting some elements should be identical
to dropping the others.
Is there anybody who can explain, why it had to be implemented that way?
Is there any chance of that getting changed in the future?

Sorry for the empty post, to much clicking without thinking.
The #select in Enumerable can only return a "general" type - in this case
an Array.

I see, but isn't that restating the problem?

I think Robert's point is that nothing other than a general type makes
sense. For example, if you select from an IO stream, you don't expect
another IO stream.
Even though "Programming Ruby" states: [snip] Enumerable#reject: returns an
array for all elements of enumObj for which block is false (see also
Enumerable#find_all) [/snip],
reject _respects_ the class it acts upon in returning a _hash_, not an array.
Not so select.
Do you see the inconsistency?

Hash overrides Enumerable#reject. I'm not sure why, except possibly
because of the relation between reject and delete_if.
Could you please elaborate into that? I do not understand.


I fail to see why, could you give an example?

Anything that depends on the output having array-like behaviors:

selected = enum.select(&select_block).flatten


David

--
* 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)
 
R

Robert Dober

Hi --



Anything that depends on the output having array-like behaviors:

selected = enum.select(&select_block).flatten
That is ok, but we are complaining about

hash.select

Please note that the notion of Enumerable#select is erroneous in this
thread, sorry for being blunt Alexander but you were talking about
Hash#select the whole time.

I think this would be a picture case for breaking backwards
compatibility in Ruby2.0
Hash#select --> returning a Hash
and we would live in a better world ;)
unless you do not like it of course.

In other words it might be interesting to know if people like this
behavior without thinking about backwards compatibility or
implementation details.

Robert
 
A

Alexander Presber

Am 21.06.2007 um 12:08 schrieb (e-mail address removed):
Hi --

Am 21.06.2007 um 11:20 schrieb Robert Klemme:
On 21.06.2007 11:06, Alexander Presber wrote:
Hello everybody,
Could you please take a look at the result of the following
statements:
irb(main):001:0> a = {'foo' => 'bar', 'baz' => 'qux'}
=> {"baz"=>"qux", "foo"=>"bar"}
irb(main):002:0> a.reject{|k,v| k=='foo' }
=> {"baz"=>"qux"}
irb(main):003:0> a.select{|k,v| k=='baz' }
=> [["baz", "qux"]]
The result of the reject statement is clearly sensible: the
original
hash minus the element with the key 'foo'.
But what about select? Shouldn't it return the same hash
(instead of
an array of key-value pairs)?
I have to concur. I've never liked that. You'd think there'd be
some
way to have Enumerable act in accordance with the class it is
effecting, rather then dropping to the "LCD" --an array.
Absolutely.
But the most baffling to me is, that it does not even act
_consistently_, see my original examples.
From a logical point of view (or at least the principle of least
surprise), selecting some elements should be identical
to dropping the others.
Is there anybody who can explain, why it had to be implemented
that way?
Is there any chance of that getting changed in the future?

Sorry for the empty post, to much clicking without thinking.
The #select in Enumerable can only return a "general" type - in
this case an Array.

I see, but isn't that restating the problem?

I think Robert's point is that nothing other than a general type makes
sense. For example, if you select from an IO stream, you don't expect
another IO stream.

Mhm. I thought IO#select is mixed in from the module Kernel, not
Enumerable. In this case, select can return whatever Kernel considers
appropriate.

I would like to think of the Enumerable mixin as an interface,
describing the general concept of "enumerability".
Rejecting and selecting certain elements of an enumerable set
certainly belong to this concept.

As I see it, a general recipe for selecting would be:
1) iterate (hence the need for enumerability) vfer the given set and
check the return value of the block for each element.
2) if true, keep, otherwise drop
3) return the resulting set, keeping all other properties (including
class) intact

Rejecting is just the opposite for 2).
Even though "Programming Ruby" states: [snip] Enumerable#reject:
returns an array for all elements of enumObj for which block is
false (see also Enumerable#find_all) [/snip],
reject _respects_ the class it acts upon in returning a _hash_,
not an array.
Not so select.
Do you see the inconsistency?

Hash overrides Enumerable#reject. I'm not sure why, except possibly
because of the relation between reject and delete_if.
Could you please elaborate into that? I do not understand.


I fail to see why, could you give an example?

Anything that depends on the output having array-like behaviors:

selected = enum.select(&select_block).flatten

I don't get what that has to do with duck typing.

The possibility to _flatten_ something requires it to be an Array-
duck, not an Enumerable-duck. That is why flatten is part of Array.
Nobody should expect the result of Enumerable#select to be flattenable.

If however there is a sensible way to make the Enumerable an Array
(in order to flatten it), you should go:

selected = enum.select(&select_block).to_a.flatten

(note the to_a)

Sincerely yours,
Alex
 
D

dblack

Hi --

That is ok, but we are complaining about

hash.select

Please note that the notion of Enumerable#select is erroneous in this
thread, sorry for being blunt Alexander but you were talking about
Hash#select the whole time.

Yes, but making a special case of Hash, as opposed to other
enumerables, is exactly what breaks duck typing. I would actually
prefer to see Hash#reject return an array.
I think this would be a picture case for breaking backwards
compatibility in Ruby2.0
Hash#select --> returning a Hash
and we would live in a better world ;)
unless you do not like it of course.

In other words it might be interesting to know if people like this
behavior without thinking about backwards compatibility or
implementation details.

I like having arrays be the "common currency" of select operations. I
don't think there's anything that you're prevented from doing as long
as that's the case.


David

--
* 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)
 
Ad

Advertisements

M

Michael Fellinger

Hi --



Yes, but making a special case of Hash, as opposed to other
enumerables, is exactly what breaks duck typing. I would actually
prefer to see Hash#reject return an array.


I like having arrays be the "common currency" of select operations. I
don't think there's anything that you're prevented from doing as long
as that's the case.

So what, making #reject return an Array as well?
 
D

dblack

Hi --

I would like to think of the Enumerable mixin as an interface, describing the
general concept of "enumerability".
Rejecting and selecting certain elements of an enumerable set certainly
belong to this concept.

As I see it, a general recipe for selecting would be:
1) iterate (hence the need for enumerability) vfer the given set and check
the return value of the block for each element.
2) if true, keep, otherwise drop
3) return the resulting set, keeping all other properties (including class)
intact

The question, though, is the representation of the "set". Any class
that mixes in Enumerable and defines #each can have a select
operation, and there's no constraint that says that such a class has
to be a collection. So you can't guarantee that the class provides a
container in which an instance can return a smaller version of itself.
I don't get what that has to do with duck typing.

The possibility to _flatten_ something requires it to be an Array-duck, not
an Enumerable-duck. That is why flatten is part of Array.
Nobody should expect the result of Enumerable#select to be flattenable.

Well, that's what we're discussing :) I expect #select to return an
array, so it's flattenable. But now I think we're going in circles.


David

--
* 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)
 
R

Robert Dober

Hi --

On Thu, 21 Jun 2007, Robert Dober wrote:
I like having arrays be the "common currency" of select operations.
don't think there's anything that you're prevented from doing as long
as that's the case.

Sure there is, I do not want to convert Arrays back to Hashes all the
time -- and I am not talking performance.

And why do I have Hash#select anyway in that case? I could very well
use Enumerable#select if I wanted the behavior you have described.

BTW Hash#to_a will not be deprecated I guess ;)

Robert
 
A

Alexander Presber

Well, that's what we're discussing :) I expect #select to return an
array, so it's flattenable. But now I think we're going in circles.

Why, of all possibities, an Array? Why not an Hash or any other class
that mixes in Enumerable?
As I wanted to point out: The Array class is in no way a special
Enumerable, but it is treated special by being the return type of
some (!) Enumerable operations.

See, not all Enumerables _are_ Arrays, it's the other way around.
It may not make much of a difference in every day coding, but if you
don't keep the two apart, then why not drop Enumerable alltogether
and always mix Array in instead?
There should be a reason Enumerable was introduced as opposed to
include it's functionality in Array?

Yours,
Alexander
 
Ad

Advertisements

D

dblack

Hi --

Why, of all possibities, an Array? Why not an Hash or any other class that
mixes in Enumerable?
As I wanted to point out: The Array class is in no way a special Enumerable,
but it is treated special by being the return type of some (!) Enumerable
operations.

See, not all Enumerables _are_ Arrays, it's the other way around.
It may not make much of a difference in every day coding, but if you don't
keep the two apart, then why not drop Enumerable alltogether and always mix
Array in instead?
There should be a reason Enumerable was introduced as opposed to include it's
functionality in Array?

But its functionality is only in Array because Array mixes in
Enumerable.


David

--
* 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)
 
Y

Yossef Mendelssohn

Yes, but making a special case of Hash, as opposed to other
enumerables, is exactly what breaks duck typing. I would actually
prefer to see Hash#reject return an array.

I like having arrays be the "common currency" of select operations. I
don't think there's anything that you're prevented from doing as long
as that's the case.

David

The inconsistency of return values between Hash#reject vs. Hash#select
has bothered me for a long time. Above all, I'd want this to be
consistent, but unlike you (and I believe like the majority), I'd like
both to return a Hash.

I'm not really sure how duck typing even enters into it as a serious
concern. The blocks given to reject/select are different based on the
Enumerable type. Consider:

irb(main):017:0> %w{red green blue}.select { |elem| elem.length > 4 }
=> ["green"]
irb(main):018:0> {:red => true, :green => true, :blue => true}.select
{ |elem| elem.length > 4 }
(irb):18: warning: multiple values for a block parameter (2 for 1)
from (irb):18
(irb):18: warning: multiple values for a block parameter (2 for 1)
from (irb):18
(irb):18: warning: multiple values for a block parameter (2 for 1)
from (irb):18
=> []

I get an Array from both, which is wonderful if I'm expecting an Array
and I want to flatten the return value or do any other Array-specific
things. The only problem is one array is useless and wrong.

irb(main):019:0> {'red' => true, 'green' => true, 'blue' =>
true}.select { |k,v| k.length > 4 }
=> [["green", true]]

So now I've selected in a more sensible way. The problem here is I
*knew* I was selecting from a Hash and wrote the block accordingly,
but now I have this Array of two-element Arrays back.

This is why I use reject with a negated block.
 
R

Robert Dober

There should be a reason Enumerable was introduced as opposed to
include it's functionality in Array?
Alexander I agree with your POV, however maybe it would do this
discussion some good to take one step back and look at the greater
picture.

Enumerable is a Mixin based on each and it implements methods like
select, map etc by using the each interface of it's client class. It
very often returns arrays than as it simply cannot do something
different - without creating a revolutionary new concept like an
Iterator but that is OffTopic

You were complaining about Hash#select returning an Array. I complain
about that too but it has nothing to do with Enumerable, Enumerable is
not used, it is implemented in Hash itself.

If we want to discuss if we like or dislike Hash#select returning an
array we shall fear to mention Enumerable as it has nothing to do with
it.
As a matter of fact it would be ridiculous - you have explained that
nicely yourself - to ask Enumerable to return Hashes.

Cheers
Robert
 
Ad

Advertisements

F

Felipe Contreras

hi everyone,

I am new to ruby, I want to installed ruby on workstation. But I am not a
super user and I don't have the access to /user/local. So I need to
change everything refer to /user/local/ to /home/fixpb.

I try to find every file contain /user/local under ruby directory and
change them . I change the configure.h. I change everything I can find but
still doesn't work. I am really frustrated now and need your
help. Thanks!

Why don't you do:
./configure --prefix=$HOME/ruby?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top