views:

156

answers:

3

Hi, I have an array of strings:

["username", "String", "password", "String"]

And I want to convert this array to a list of Field objects:

class Field
    attr_reader :name, :type
    def initialize(name, type)
        @name = name
        @type = type
    end
end

So I need to map "username", "String" => Field.new("username", "String") and so on. The length of the array will always be a multiple of two.

Does anyone know if this is possible using a map style method call?

+2  A: 

Take a look at each_slice. It should do what you need.

Matt Grande
1.9 only, FWIW. Too bad there isn't a map_slice, which is what he's really after.
Dave Ray
Maybe 1.8.7 too, I'm not sure.
Dave Ray
each_slice is in 1.8.6 too, if you `require 'enumerator'` (stdlib)
sepp2k
It's 1.8.6. Definitely not 1.9, the docs I linked are for 1.8.7
Matt Grande
+3  A: 

A bracketed Hash call does exactly what you need. Given

a = ["username", "String", "password", "String"]

Then:

fields = Hash[*a].map { |name, type| Field.new name, type }
Magnar
Thanks Magnar, an interesting solution that I didn't know existed. I'm going to go with sepp2k's answer as it is more generic. As far as I can see this will only handle the case where there is two object mapping to one, or am I wrong? Could you map say four strings to one object using this method?
Brian Heylin
The Hash-bracket constructor creates a hash of key=>value pairs out of every other value in the array. So it's perfect for your example, but no, it won't work for larger constructors.
Magnar
+2  A: 

1.8.6:

require 'enumerator'
result = []
arr = ["username", "String", "password", "String"]
arr.each_slice(2) {|name, type| result << Field.new(name, type) }

Or Magnar's solution which is a bit shorter.

For 1.8.7+ you can do:

arr.each_slice(2).map {|name, type| Field.new(name, type) }
sepp2k
Excellent that's what I'm looking for. I'm choosing this as the answer as it is more scalable that the Hash method for mapping multiple items to an object.
Brian Heylin