93fc84c261cdce2e2f1d64c8e531ecb7

First posting here. I just wondered if there were a cleaner way to do the following. I looks a bit ugly to me.

The FIELDS need to be converted to symbols and become the keys of each hash. Each nested array in the DATA array becomes the data in each hash.

FIELDS = [ 'first', 'last',      'band' ]
DATA   = [['Kurt',  'Cobain',    'Nirvana'],
          ['Jimi',  'Page',      'Led Zeppelin'],
          ['Noel',  'Gallagher', 'Oasis'],
          ['Thom',  'Yorke',     'Radiohead']]

def combine_fields_and_data(fields, data)
  new_data = []
  data.each do |row|
    row_hash = {}
    row.each_with_index do |column, i| 
      row_hash[fields[i].to_sym] = column
    end
    new_data.push(row_hash)
  end
  return new_data
end

Refactorings

No refactoring yet !

880cbab435f00197613c9cc2065b4f5a

danielharan

September 22, 2008, September 22, 2008 16:00, permalink

1 rating. Login to rate!

Wrap that in an object lets the BandMember know how to handle the order of params, rather than having that in the loop.

class BandMember
  attr_accessor :first, :last, :band
  def initialize(first, last, band)
    @first, @last, @band = first, last, band
  end
end

DATA.map {|row| BandMember.new(*row) }

# Alternately, with no new class:

def datum_to_band_member(first, last, band)
  {:first => first, :last => last, :band => band}
end

DATA.collect {|e| datum_to_band_member *e }
C54b1538124ee5c6f3af5f628e1750dc

ruphin.myopenid.com

September 22, 2008, September 22, 2008 16:13, permalink

2 ratings. Login to rate!

I think this works. It uses Enumerable.zip to get the Arrays in a right format to just make a new Hash.

def combine_fields_and_data(fields, data)
  new_data = []
  data.each do |row|
    new_data << Hash[fields.zip(row)]
  end
  return new_data
end
93fc84c261cdce2e2f1d64c8e531ecb7

charlesroper

September 22, 2008, September 22, 2008 16:54, permalink

No rating. Login to rate!

OK, good stuff. Elegant solutions. Many thanks! Now what if I don't know the number of fields or their names in advance? In other words, I've pulled the fields and the data from a database table but I don't know what that table contains. Ruphin's solution covers this scenario whereas Daniel's does not.

880cbab435f00197613c9cc2065b4f5a

danielharan

September 22, 2008, September 22, 2008 17:07, permalink

No rating. Login to rate!

It's rather odd not to know what's in your database :O

I couldn't get ruphin's code to work. That said, if it's with an ORM like ActiveRecord, there are built-in methods to get attributes in a hash format.

A8d3f35baafdaea851914b17dae9e1fc

Adam

September 22, 2008, September 22, 2008 17:11, permalink

2 ratings. Login to rate!
def combine_fields_and_data(fields, data)
  data.map { |row| Hash[*fields.zip(row).flatten] }
end
A8d3f35baafdaea851914b17dae9e1fc

Adam

September 22, 2008, September 22, 2008 17:12, permalink

2 ratings. Login to rate!

Alternatively, if you like danielharan's first solution, you can load the field names at runtime like this:

BandMember = Struct.new(*FIELDS.map { |field| field.to_sym })
DATA.map { |row| BandMember.new(*row) }
93fc84c261cdce2e2f1d64c8e531ecb7

charlesroper

September 22, 2008, September 22, 2008 17:42, permalink

No rating. Login to rate!

Brilliant! The refactoring brainpower in here is awesome. I'm constantly amazed at how elegant Ruby can be.

Daniel, it's interesting you couldn't get Ruphin's solution to work as it worked just fine for me. Adam, I've not looked at structs before; I'll have go get the full skinny on them. Thanks for the pointer.

And yes, I agree it is odd not knowing what's in my database, but that's the particular situation I'm faced with. :)

C54b1538124ee5c6f3af5f628e1750dc

ruphin.myopenid.com

September 22, 2008, September 22, 2008 23:29, permalink

No rating. Login to rate!

My solution was based on something similar to what Adam posted. I couldn't get that particular code to work, but I used that same method with zip and flatten to end up with what I posted, that's the only version I could get working.

93fc84c261cdce2e2f1d64c8e531ecb7

charlesroper

September 23, 2008, September 23, 2008 14:38, permalink

No rating. Login to rate!

One minor point regarding Adam's solution: the keys aren't converted to symbols. Here's what I've done; is this the best way?

def combine_fields_and_data(fields, data)
  fields.collect! { |f| f.to_sym }
  data.map { |row| Hash[*fields.zip(row).flatten] }
end

Your refactoring





Format Copy from initial code

or Cancel