# Hash pairs at?

Discussion in 'Ruby' started by Trans, Jan 21, 2007.

1. ### TransGuest

Seesm like there should be a mehtod for this:

h = { :a=>1, :b=>2, :c=>3 }

h.what_methoda, :c) #=> { :a=>1, :c=>3 }
^^^^^^^^^^^

Or is there some other simple way we're supposed to do this?

T.

Trans, Jan 21, 2007

2. ### Chris CarterGuest

On 1/20/07, Trans <> wrote:
> Seesm like there should be a mehtod for this:
>
> h = { :a=>1, :b=>2, :c=>3 }
>
> h.what_methoda, :c) #=> { :a=>1, :c=>3 }
> ^^^^^^^^^^^
>
> Or is there some other simple way we're supposed to do this?
>
> T.
>
>
>

http://concentrationstudios.com/2006/12/20/12-days-of-stupid-ruby-tricks

Check out Day 11

--
Chris Carter
concentrationstudios.com
brynmawrcs.com

Chris Carter, Jan 21, 2007

3. ### William JamesGuest

Trans wrote:
> Seesm like there should be a mehtod for this:
>
> h = { :a=>1, :b=>2, :c=>3 }
>
> h.what_methoda, :c) #=> { :a=>1, :c=>3 }
> ^^^^^^^^^^^
>
> Or is there some other simple way we're supposed to do this?
>
> T.

h = { :a,1, :b,2, :c,3 }
==>{:c=>3, :a=>1, :b=>2}
h.reject{|k,v| ![:a,:c].include? k}
==>{:c=>3, :a=>1}

William James, Jan 21, 2007
4. ### Joel VanderWerfGuest

Trans wrote:
> Seesm like there should be a mehtod for this:
>
> h = { :a=>1, :b=>2, :c=>3 }
>
> h.what_methoda, :c) #=> { :a=>1, :c=>3 }
> ^^^^^^^^^^^
>
> Or is there some other simple way we're supposed to do this?
>
> T.
>

h = { :a=>1, :b=>2, :c=>3 }

class Hash
def restrict(*keys)
keys.inject({}) {|h,k| h[k] = self[k]; h}
# alternative:
#Hash[*keys.zip(values_at(*keys)).flatten]
end
end

p h.restricta, :c) #=> { :a=>1, :c=>3 }

Maybe there should be something like this in the core?

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

Joel VanderWerf, Jan 21, 2007
5. ### ggaGuest

Trans ha escrito:
> Seesm like there should be a mehtod for this:

No.

>
> Or is there some other simple way we're supposed to do this?
>
> T.

[:a, :c].inject({}) { |s, x| s[x] = h[x]; s }

gga, Jan 21, 2007
6. ### ggaGuest

gga wrote:
> Trans ha escrito:
> > Seesm like there should be a mehtod for this:

>
> No.
>

That being said, Hash DOES seem to be buggy and missing a proper
find_all method.

irb> h.find_all { |k,v| [:a,:c].include?(k) }
=> [[:c, 3], [:a, 1]] # incorrect, it is returning an array, not a
hash

irb> h.reject { |k,v| ![:a,:c].include?(k) }
{:c=>3, :a=>1} # correct

gga, Jan 21, 2007
7. ### Guest

Hi --

On Sun, 21 Jan 2007, gga wrote:

>
> gga wrote:
>> Trans ha escrito:
>>> Seesm like there should be a mehtod for this:

>>
>> No.
>>

>
> That being said, Hash DOES seem to be buggy and missing a proper
> find_all method.
>
> irb> h.find_all { |k,v| [:a,:c].include?(k) }
> => [[:c, 3], [:a, 1]] # incorrect, it is returning an array, not a
> hash

It's not incorrect or buggy; that's the way Enumerable#find_all works.
In addition to being Enumerables themselves, arrays serve as the
common container for the results of lots of different Enumerables.

It could work otherwise (at least for hashes, though not in the
general Enumerable case), but it works this way by design, not by
accident.

David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Jan 21, 2007
8. ### PhrogzGuest

Trans wrote:
> Seesm like there should be a mehtod for this:
>
> h = { :a=>1, :b=>2, :c=>3 }
>
> h.what_methoda, :c) #=> { :a=>1, :c=>3 }
> ^^^^^^^^^^^

# h = { :a=>'a', :b=>'b', :c=>'c' }
# p h.entries( :a, :c, :d )
# #=> { :d=>nil, :a=>'a', :c=>'c' }
class Hash
def entries( *keys )
self.class[ *keys.zip( values_at( *keys ) ).flatten ]
end
end

Phrogz, Jan 21, 2007
9. ### PhrogzGuest

Phrogz wrote:
> Trans wrote:
> > Seems like there should be a mehtod for this:

> class Hash
> def entries( *keys )
> self.class[ *keys.zip( values_at( *keys ) ).flatten ]
> end
> end

Oh, and yes: I'd like a method like this in the core, also. Preferably
with a more elegant, faster implementation than the above. I find this
quite useful sometimes. A recent example that comes to mind is taking
the params hash in Rails and specifying a specific subset of the
populated values to pass on to another method.

Phrogz, Jan 21, 2007
10. ### Guest

Hi --

On Mon, 22 Jan 2007, Phrogz wrote:

> Phrogz wrote:
>> Trans wrote:
>>> Seems like there should be a mehtod for this:

>> class Hash
>> def entries( *keys )
>> self.class[ *keys.zip( values_at( *keys ) ).flatten ]
>> end
>> end

>
> Oh, and yes: I'd like a method like this in the core, also. Preferably
> with a more elegant, faster implementation than the above. I find this
> quite useful sometimes. A recent example that comes to mind is taking
> the params hash in Rails and specifying a specific subset of the
> populated values to pass on to another method.

I'll put in a plug here for flattenx, which lets you flatten by any
number of levels so that you could do the above without the
over-flattening vulnerability.

http://raa.ruby-lang.org/project/flattenx/

David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Jan 21, 2007
11. ### PhrogzGuest

Flattenx [was Re: Hash pairs at?]

wrote:
> I'll put in a plug here for flattenx, which lets you flatten by any
> number of levels so that you could do the above without the
> over-flattening vulnerability.
>
> http://raa.ruby-lang.org/project/flattenx/

Yes, yes! I've used this locally, and wanted to rely on this remotely,
many times!

This, too, should be in the core (particularly since it requires
compilation, and is not a pure-ruby solution.)

Phrogz, Jan 21, 2007
12. ### TransGuest

Robert Dober wrote:

> I'd rather see it in the core
> I have a slight preference for #pairs_at, #entries is not a bad name, but I
> feel the first is more descriptive.

I agree. I think #paris_at is easier to quicky comprehend.

Also, I recalled I had added another method to facets that can do this
too. I was writing Hash#| and thought I should go ahead and wrote an #&
too if reasonable. And lo! There it was:

h = {:a=>1,:b=>2,:c=>3}
h & [:a,:b] #=> {:a=>1,:b=>2}

Code for facets/core/hash/op_and.rb (also op_or.rb):

class Hash
def &(other)
case other
when Array
k = (keys & other)
Hash[*(k.zip(values_at(*k)).flatten)]
else
Hash.new[*(to_a & other.to_a).flatten]
end
end

def |(other)
other.merge self
end
end

Think I still prefer the readability of #pairs_at however. But the
above is good to have too.

T.

Trans, Jan 21, 2007
13. ### ggaGuest

wrote:

>
> It's not incorrect or buggy; that's the way Enumerable#find_all works.
> In addition to being Enumerables themselves, arrays serve as the
> common container for the results of lots of different Enumerables.
>

Sorry, David, but I disagree. It may not be buggy (as the bugginess is
properly documented , but it is certainly incorrect. Re-read my
post.
Hash.reject, which is also an Enumerable, DOES return a hash.
Hash.find_all which is algorithmically the same as Hash.reject but
without a negation, does not.
Someone forgot to override find_all in the Hash case, but did remember
to do it for Hash.reject. Or, if you are of the belief that indeed
Enumerables should always return an array, Hash.reject was incorrectly
overridden when it shouldn't have been.

gga, Jan 21, 2007
14. ### Joel VanderWerfGuest

gga wrote:
> wrote:
>
>> It's not incorrect or buggy; that's the way Enumerable#find_all works.
>> In addition to being Enumerables themselves, arrays serve as the
>> common container for the results of lots of different Enumerables.
>>

>
> Sorry, David, but I disagree. It may not be buggy (as the bugginess is
> properly documented , but it is certainly incorrect. Re-read my
> post.
> Hash.reject, which is also an Enumerable, DOES return a hash.
> Hash.find_all which is algorithmically the same as Hash.reject but
> without a negation, does not.
> Someone forgot to override find_all in the Hash case, but did remember
> to do it for Hash.reject. Or, if you are of the belief that indeed
> Enumerables should always return an array, Hash.reject was incorrectly
> overridden when it shouldn't have been.

This does look a bit odd...

irb(main):001:0> h = {1=>3, 5=>7}
=> {5=>7, 1=>3}
irb(main):002:0> h.reject {|k,v| k==1}
=> {5=>7}
irb(main):003:0> h.select {|k,v| k==1}
=> [[1, 3]]

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

Joel VanderWerf, Jan 21, 2007
15. ### William JamesGuest

wrote:
> Hi --
>
> On Mon, 22 Jan 2007, Phrogz wrote:
>
> > Phrogz wrote:
> >> Trans wrote:
> >>> Seems like there should be a mehtod for this:
> >> class Hash
> >> def entries( *keys )
> >> self.class[ *keys.zip( values_at( *keys ) ).flatten ]
> >> end
> >> end

> >
> > Oh, and yes: I'd like a method like this in the core, also. Preferably
> > with a more elegant, faster implementation than the above. I find this
> > quite useful sometimes. A recent example that comes to mind is taking
> > the params hash in Rails and specifying a specific subset of the
> > populated values to pass on to another method.

>
> I'll put in a plug here for flattenx, which lets you flatten by any
> number of levels so that you could do the above without the
> over-flattening vulnerability.
>
> http://raa.ruby-lang.org/project/flattenx/

class Array
def flatten_1
inject([]){|a,x| Array(x).each{|e| a<<e}; a}
end
end

p [[[[22],33],44], %w(aa bb cc), [88,[99,55]], 3.14].flatten_1

--- output -----
[[[22], 33], 44, "aa", "bb", "cc", 88, [99, 55], 3.14]

William James, Jan 21, 2007
16. ### Guest

Hi --

On Mon, 22 Jan 2007, William James wrote:

> wrote:
>>
>> I'll put in a plug here for flattenx, which lets you flatten by any
>> number of levels so that you could do the above without the
>> over-flattening vulnerability.
>>
>> http://raa.ruby-lang.org/project/flattenx/

>
> class Array
> def flatten_1
> inject([]){|a,x| Array(x).each{|e| a<<e}; a}
> end
> end
>
> p [[[[22],33],44], %w(aa bb cc), [88,[99,55]], 3.14].flatten_1
>
> --- output -----
> [[[22], 33], 44, "aa", "bb", "cc", 88, [99, 55], 3.14]

That's the idea, though flattenx lets you do flatten_by(n) and also is
written in C for speed.

David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Jan 21, 2007
17. ### Guest

Hi --

On Mon, 22 Jan 2007, Joel VanderWerf wrote:

> gga wrote:
>> wrote:
>>
>>> It's not incorrect or buggy; that's the way Enumerable#find_all works.
>>> In addition to being Enumerables themselves, arrays serve as the
>>> common container for the results of lots of different Enumerables.
>>>

>>
>> Sorry, David, but I disagree. It may not be buggy (as the bugginess is
>> properly documented , but it is certainly incorrect. Re-read my
>> post.
>> Hash.reject, which is also an Enumerable, DOES return a hash.
>> Hash.find_all which is algorithmically the same as Hash.reject but
>> without a negation, does not.
>> Someone forgot to override find_all in the Hash case, but did remember
>> to do it for Hash.reject. Or, if you are of the belief that indeed
>> Enumerables should always return an array, Hash.reject was incorrectly
>> overridden when it shouldn't have been.

>
> This does look a bit odd...
>
> irb(main):001:0> h = {1=>3, 5=>7}
> => {5=>7, 1=>3}
> irb(main):002:0> h.reject {|k,v| k==1}
> => {5=>7}
> irb(main):003:0> h.select {|k,v| k==1}
> => [[1, 3]]

A bit. The funny thing, though, is that it of course makes it
possible to do either -- so the irregularity actually provides a kind
of resilience. The consistent version, should it ever come into
being, will shut the door on one of them.

I know that people don't want to do select { not } and so on... so
I can see that it's not really ideal. But it's kind of fascinating
that "fixing" it, in either direction, would result in a net loss of
functionality.

David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Jan 21, 2007
18. ### TransGuest

wrote:
> Hi --
>
> On Mon, 22 Jan 2007, Joel VanderWerf wrote:
>
> > gga wrote:
> >> wrote:
> >>
> >>> It's not incorrect or buggy; that's the way Enumerable#find_all works.
> >>> In addition to being Enumerables themselves, arrays serve as the
> >>> common container for the results of lots of different Enumerables.
> >>>
> >>
> >> Sorry, David, but I disagree. It may not be buggy (as the bugginess is
> >> properly documented , but it is certainly incorrect. Re-read my
> >> post.
> >> Hash.reject, which is also an Enumerable, DOES return a hash.
> >> Hash.find_all which is algorithmically the same as Hash.reject but
> >> without a negation, does not.
> >> Someone forgot to override find_all in the Hash case, but did remember
> >> to do it for Hash.reject. Or, if you are of the belief that indeed
> >> Enumerables should always return an array, Hash.reject was incorrectly
> >> overridden when it shouldn't have been.

> >
> > This does look a bit odd...
> >
> > irb(main):001:0> h = {1=>3, 5=>7}
> > => {5=>7, 1=>3}
> > irb(main):002:0> h.reject {|k,v| k==1}
> > => {5=>7}
> > irb(main):003:0> h.select {|k,v| k==1}
> > => [[1, 3]]

>
> A bit. The funny thing, though, is that it of course makes it
> possible to do either -- so the irregularity actually provides a kind
> of resilience. The consistent version, should it ever come into
> being, will shut the door on one of them.
>
> I know that people don't want to do select { not } and so on... so
> I can see that it's not really ideal. But it's kind of fascinating
> that "fixing" it, in either direction, would result in a net loss of
> functionality.

Avoiding net loss, how about going for gross gain. So how about "fixing
it" so there is both?

select
select_pair

And {meth}_pair could also work for assoc arrays too.

T.

Trans, Jan 21, 2007
19. ### Guest

On Jan 21, 2007, at 3:50 PM, wrote:
> That's the idea, though flattenx lets you do flatten_by(n) and also is
> written in C for speed.

I didn't see anyone else mention that in Ruby 1.9...

\$ ri-1.9 Array#flatten
---------------------------------------------------------- Array#flatten
array.flatten -> an_array
array.flatten(level) -> an_array
------------------------------------------------------------------------
Returns a new array that is a one-dimensional flattening of this
array (recursively). That is, for every element that is an array,
extract its elements into the new array. If the optional _level_
argument determins the level of recursion to flatten.

Gary Wright

, Jan 21, 2007
20. ### Guest

Hi --

On Mon, 22 Jan 2007, wrote:

>
> On Jan 21, 2007, at 3:50 PM, wrote:
>> That's the idea, though flattenx lets you do flatten_by(n) and also is
>> written in C for speed.

>
> I didn't see anyone else mention that in Ruby 1.9...
>
> \$ ri-1.9 Array#flatten
> ---------------------------------------------------------- Array#flatten
> array.flatten -> an_array
> array.flatten(level) -> an_array
> ------------------------------------------------------------------------
> Returns a new array that is a one-dimensional flattening of this
> array (recursively). That is, for every element that is an array,
> extract its elements into the new array. If the optional _level_
> argument determins the level of recursion to flatten.

Cool! I actually didn't know that had made it into 1.9. I look
forward to retiring flattenx

David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

, Jan 21, 2007