From: Dirk Traulsen Date: 2008-01-30T22:08:13+09:00 Subject: Re: Proposal/RFQ: Hash#values/keys with block Am 30 Jan 2008 um 4:20 hat Robert Klemme geschrieben: > On 29.01.2008 18:29, Dirk Traulsen wrote: > > Am 29 Jan 2008 um 22:50 hat Robert Klemme geschrieben: > > > >> I am waiting to see whether this is generally needed. As far as > >> I remember this has not been suggested before. If there is no > >> overwhelming request for this I opt for not making this standard. > > > > Why make it standard? (...) > > 3. Speed > > I think that this will not slow down ruby as a whole, but I'm sure > > that > > hash.values {|k,v| v % 2 == 0 } > > > > would be definitely faster than > > > > hash.select {|k,v| v % 2 == 0 }.map {|k,v| v} > > > > especially with big hashes, because you make only one array > > directely, not two and don't have to call map additionally. > > You would be surprised to see how fast seemingly more complex bits of > code often are. I myself have been surprised in the past. > > > And let us not begin about inject and speed.. > > See? #inject can often be used to avoid multiple traversals but yet > often a combination with #map is faster. :-) That's true. So this has to be proven by implementation. > > 4. Rubyness > > This is difficult to describe, but one point I really, really like > > about Ruby is blocks. There are a lot of methods in the standard > > library which use blocks to 'finetune' the method. > > Use them pure and you get all of it. > > Or use them with a block and you get a subset or a modified > > result. > > I am not sure I agree here. If you take #each or #select, these do > not make any sense without a block so the block is certainly not fine > tuning the method. What examples do you have in mind? Below I put a few examples. I'm sure if I would really dive into the standard lib, there might be better ones, but these came to my mind. h1 = { "a" => 20, "b" => 10 } h2 = { "b" => 25, "c" => 30 } #Enumerable#grep p h1.grep(Array) #=> [["a", 20], ["b", 10]] p h1.grep(Array) {|(k,v)| v } #=> [20, 10] #Hash#merge p h1.merge(h2) #=>{"a"=>20, "b"=>25, "c"=>30} p h1.merge(h2){|k,ov,nv| nv=ov if ov{"a"=>20, "b"=>10, "c"=>30} #Hash#fetch p h1.fetch("z") rescue p $! #=> # p h1.fetch("z") {|v| 'wrong key'} #=> "wrong key" #Hash#sort p h1.sort #=> [["a", 20], ["b", 10]] p h1.sort {|(k,v),(k2,v2)| v <=> v2} #=> [["b", 10], ["a", 20]] > My soft point here is, that it somehow feels odd to combine two > completely orthogonal things (key extraction and entry selection) in a > single method to me. It does not feel orthogonal for me. This is a combination, true, but I would not call it orthogonal. In real life most tasks are combinatory. Ruby has a lot of constructs which mimic human thinking and use this for a more intuitive access to programming. Intuitively for me hash.keys {|k,v| v > 200 } was the same as hash.select {|k.v| v > 200 } Just the returned values differ. Hash#select gives you the chosen key-value pairs in an array and Hash#keys/values with a block only the chosen keys or values. (...) > > Robert, don't you think it would fit nicely in the standard lib? > > I would not say that it does not fit but I am not totally convinced. > I am trying to employ public debate to find out the best solution. > :-) Well, it seems it is more of a private debate. I'm a little disappointed by this lack of interest. Do you think I should have posted it to ruby-core? > Dirk, I am glad that once again there is an interesting discussion. > Thanks for that! Thanks a lot for your comments. Kind regards Dirk