hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

Petty Theft from Python #

by why in bits

Lucas Carlson has lifted a few method ideas from Python: starts_with? and ends_withs?, as well as in?. Which got me thinking about an unfinished thought from FOSCON. I’d really like Python’s dict method.

Python’s Dictzip maneuvre:

 >> keys = ['a', 'b', 'c']
 >> values = [1, 2, 3]
 >> dict(zip(keys, values))
 => {'a': 1, 'b': 2, 'c': 3} 

A Ruby translation might go like:

 >> keys = ['a', 'b', 'c']
 >> values = [1, 2, 3]
 >> Hash[keys.zip(values)]
 => {'a' => 1, 'b' => 2, 'c' => 3}

Here’s the code:

  def Hash.[]( enum )
    enum.inject({}) do |hsh,(k,v)| 
      hsh[k] = v
      hsh
    end
 end

I know there’s already a Hash::[] but I really like this better. An array of pairs makes so much more sense than a flattened array of arbitrary length.

said on 06 Sep 2005 at 16:34

Yeah, I think so too.

However, the existing Hash::[] is good for hacks like that HOSTS thing from hoodlum/mouseHole.

So, I’m a bit torn. I kind of wish we could have both, but there would be some uncomfortable ambiguities.

said on 06 Sep 2005 at 16:36
We don’t need another method. We need Ruby’s Hash to handle slices:
>> require "hashslice" 
>> keys = ['a', 'b', 'c']
>> vals = [1, 2, 3]

>> h = {}
>> h[*keys] = *vals

=> {"a"=>1, "b"=>2, "c"=>3}
said on 06 Sep 2005 at 16:51

Heh.

 >> (h = {})[*keys] = *vals

Okay.

said on 06 Sep 2005 at 17:08

Like this?

h[*keys] = vals

or

*h[*keys] = *vals

class Hash
  alias old_ary_get []
  def [](*keys)
    if keys.size == 1
      old_ary_get(keys.first)
    else
      keys.map {|k| old_ary_get(k) }
    end
  end
  alias old_ary_set []=
  def []=(*args)
    case args.size
    when 0, 1
      raise ArgumentError.new("wrong number of arguments (#{args.size} for 2)")
    when 2
      old_ary_set(*args)
    else
      rhs = args.pop
      args.each_with_index {|key, i| old_ary_set(key, rhs[i]) }
    end
  end
end
said on 06 Sep 2005 at 17:10

Daniel: Yes, that would be good too. And very practical.


class Hash
  alias _get []
  alias _assign []=

  def []( *keys )
    case keys.size
    when 1
      _get keys.first
    when 0
      raise ArgumentError, "wrong number of arguments (0 for 1)
    else
      keys.map { |key| _get key }
    end
  end

  def []=( *keys )
    rhs = keys.pop
    values = rhs.to_a
    keys.each_with_index do |key, i|
      _assign key, values[i]
    end
    rhs
  end
end

Does that look about right?

Array slices would be nice too, but I’m not sure how well that would work with the two-argument forms of Array#[] and Array#[]=.

said on 06 Sep 2005 at 17:12

Bloody heck. I get up to take a break before posting and someone steals my brain.

Good show Dave. :)

said on 06 Sep 2005 at 17:14

Dave: how about we use my Hash#[] and your Hash#[]=? You forgot to return rhs in yours though…

said on 06 Sep 2005 at 17:19

Scary how close we both came, though. Variables and all.

In RedHanded, has why discovered the resonant frequency of the human brain!?

Are you prepared for the terrible secret of RUBY !?

said on 06 Sep 2005 at 17:25

Thinking about Array#[], the way you would have to use it for slicing would be somearray[[1, 2]] to avoid ambiguity with somearray[1, 2].

I wonder whether there’s a more consistent way to manage slicing between arrays and hashes?

said on 06 Sep 2005 at 17:28

If only we could have additional arguments for non-indexing setters… (a la somearray.section(1, 2) = 'a', 'b')

said on 06 Sep 2005 at 17:34

It’s not my code, btw. The “hashslice” package is by Michael Granger, available on the RAA .

said on 06 Sep 2005 at 18:00

I like ours better than Granger’s, MenTaLguY. Of course, the only real differences returning rhs (which Granger’s hashslice fails to do) and error throwing (I think a 0-length slice should be allowed, despite my []= code).

I just have to add that I think it’s cool you can do obj[foo, bar] = baz, quux and baz, quux will be arrayified.

said on 06 Sep 2005 at 19:01

http://groups.google.com/group/comp.lang.ruby/browse_frm/thread/8cd6f94516d054ac

said on 06 Sep 2005 at 19:02

Regarding the original: I think it is commonly done as Hash[*pairs.flatten] in Ruby.

said on 06 Sep 2005 at 19:14

flgr:

 class Enumerable
   alias_method :smash_deeply!, :flatten
 end

Dave Burt, MenTaLguY: You are miracles.

said on 06 Sep 2005 at 21:30

Nano Methods has just about all of these concepts, from slicingg with hash#[]= and array#[[]] to the orginal request in Hash.zipnew.

Improvements to implementations are great esteemed.

said on 07 Sep 2005 at 01:18

That’s funny! I just added a patch for this to rails the other day..

said on 07 Sep 2005 at 07:21

why: I dunno, I suggested Hash.from_assoc a while ago, IIRC .

said on 10 Sep 2005 at 04:05

Also kind of start/end-with: ar = [“abcc”, “abc”]; ar.delete_if { |i| /^a.c$/.match(i) }; puts ar (may be interesting to Ruby beginners)

said on 12 Sep 2005 at 07:50

jot: Sometimes it’s better to use [^ ] instead of . (which will also match a space)!

said on 13 Sep 2005 at 04:36

And don’t forget this one as well: rxp = Regexp.new(/ruby/, “i”); puts rxp.inspect

Comments are closed for this entry.