Associative array naming indirection

I have an array of names in string form as an instance var. The class
the array is in has a method that takes an array of string values.

I want to construct an associative array such that the names in the
first array are the keys to the values in the received array.

this throws an error:

def initialize
@labels = [‘prov’, ‘area’, ‘zone’, district’, ‘postalcode’,
‘city_prov’, ‘addr’]
@pageData = {}
end

def adddata(data)
max = data.length
max -= 1
0.upto(max) {|i| @pageData[@labels[i]] => data[i] }
end


obviously, some giant conceptual leap needs to be made, or its a
miniscule typo. (methinks the former)

Anyone got advice?

On Jun 19, 2006, at 3:51 PM, dan donaldson wrote:

‘city_prov’, ‘addr’]

obviously, some giant conceptual leap needs to be made, or its a
miniscule typo. (methinks the former)

Anyone got advice?

It’s hard to know without the error, but adddata() doesn’t look great
to me. Try something like this:
def add_data(data)
data.each_index do |index|
@pageData[@labels[i]] = data[i]
end
end

-Mat

dan donaldson wrote:

‘city_prov’, ‘addr’]

obviously, some giant conceptual leap needs to be made, or its a
miniscule typo. (methinks the former)

Anyone got advice?

What error? When?

-Justin

uh … what’s the error

dan donaldson wrote:

‘city_prov’, ‘addr’]
@pageData = {}
end

def adddata(data)
max = data.length
max -= 1
0.upto(max) {|i| @pageData[@labels[i]] => data[i] }
end

def add_data(data)
Hash[*@labels.zip(data).flatten]
end

Hash.[] takes an argument list with the even items being the keys and
the odd items the values of the hash, i.e.

Hash[:a, 1, :b, 2, :c, 3] => {:a => 1, :b => 2, :c => 3}

The asterisk turns an array into an argument list, i.e.

foo(*[:a, :b, :c])

is the same as

foo(:a, :b, :c)

You can read about Array#zip and Array#flatten on the documentation
pages, or by using ri from the terminal, e.g.

$ ri Array#zip

Cheers,
Daniel

On Jun 19, 2006, at 20:51, dan donaldson wrote:

‘city_prov’, ‘addr’]

obviously, some giant conceptual leap needs to be made, or its a
miniscule typo. (methinks the former)

It’s the typos, I’m afraid. First, you’ve got an unterminated string
literal on ‘district’.

Second you’re using the wrong syntax for hash assignment, the =>
notation is used for hash literal values. It should look like this:
@pageData[“something”] = “something else”

There’s also no reason to use #upto here - check the docs for Array
and Enumerable, there are lots of methods which don’t require you to
fiddle with finding sizes and the associated potential of fencepost
errors. I’d do this, if it were me:

def add_data(data)
@page_data[*@labels.zip(data).flatten]
end

Basically, zip combines the two arrays to something like this: [[‘a’,
1], [‘b’, 2]], flatten changes this to [‘a’, 1, ‘b’, 2], and the *
transforms that from an array to a list (of arguments) to the Hash#[]
method, which creates a new hash from that list of arguments.

matthew smillie.

docs for Array: class Array - RDoc Documentation
docs for Enumerable: module Enumerable - RDoc Documentation
docs for Hash: class Hash - RDoc Documentation

Matthew S. wrote:

On Jun 19, 2006, at 20:51, dan donaldson wrote:

‘city_prov’, ‘addr’]

obviously, some giant conceptual leap needs to be made, or its a
miniscule typo. (methinks the former)

It’s the typos, I’m afraid. First, you’ve got an unterminated string
literal on ‘district’.

Ah yes.

The typo was in fact introduced during the editing of the copy/pasted
text which contained a prefix that revealed the client’s name.

But it was in fact the ‘=>’ operator. Thanks for pointing that out.
Thanks also to everyone else, and esp. to Daniel, I’ll absorb what you
wrote as well. A one line solution, that’s elegance. I imagine that if
there’s a problem with the two arrays being of different lengths, I
could truncate the longer one.

Related: The reason for futzing with .upto() was to deal with a variable
length of input array needing to access labels in a given order. Is
there a better way?

Working now. First post to the Ruby community: nice responses. I think I
may like this.

Related: The reason for futzing with .upto() was to deal with a
variable
length of input array needing to access labels in a given order. Is
there a better way?

That depends. If having ‘nil’ values in your hash is OK, you could
still use #zip

labels = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]
data = [1, 2, 3]
Hash[*labels.zip(data).flatten]
=> {“a”=>1, “b”=>2, “c”=>3, “d”=>nil, “e”=>nil, “f”=>nil}

or #inject, if you’re feeling slightly obscurantist.

labels.inject({}) { |hsh, label| hsh.merge({label => data.shift}) }
=> {“a”=>1, “b”=>2, “c”=>3, “d”=>nil, “e”=>nil, “f”=>nil}

Or one of the other iteration methods in Array and Enumerable.

data.each_index { |idx| hsh[labels[idx]] = data[idx] }
data.each_with_index { |datum, idx| hsh[labels[idx] = datum }
hsh
=> {“a”=>1, “b”=>2, “c”=>3}

Browse through the docs, they’re the most help in situations like this.

matthew smillie.