jmccartie
jmccartie

Reputation: 4976

Looping and creating an array in Ruby

Trying to port some old PHP code to Ruby and missing some key info on creating arrays in Ruby.

The PHP code:

foreach ($results as $r) {
    $array[$r['column']][] = $r
}

Is this the simplest way to do it in Ruby? Do I have to initialize the second array?

@array = []
result.each do |r|
  @array[r.cron_column] = []
  @array[r.cron_column] << r
end

I figure this is a simple syntax issue, but my Googling has turned up empty. Thanks for your help!

Upvotes: 0

Views: 4182

Answers (3)

DigitalRoss
DigitalRoss

Reputation: 146231

array = results.inject([]) { |m, r| m[r.column] = r; m }

Update: oh, e1[] = e2 adds a new array element in PHP, so tokland is right, in which case:

array = results.inject([]) { |m, r| (m[r.column] ||= []) << r; m }

Upvotes: 0

tokland
tokland

Reputation: 67900

Are you sure you need an array as output? it would appear a hash would be more convenient; moreover, it's way easier to build in your scenario (which is usually a sign you are in the correct path):

# example
results = [
  OpenStruct.new(:x => 1, :cron_column => 0), 
  OpenStruct.new(:x => 2, :cron_column => 1), 
  OpenStruct.new(:x => 3, :cron_column => 1),
] 

@array = results.group_by(&:cron_column)
# {0=>[#<OpenStruct x=1, cron_column=0>], 
#  1=>[#<OpenStruct x=2, cron_column=1>, #<OpenStruct x=3, cron_column=1>]}

If cron_column "has no holes" (that's it, you have values from 0 to N), you can easily create an array with this same idea: results.group_by(&:cron_column).sort.map { |k, v| v } or results.group_by(&:cron_column).sort.map(&:last), as you prefer.

Upvotes: 0

Ed Swangren
Ed Swangren

Reputation: 124790

You are indexing into an empty array, so that will always return nil. nil does not define the << operator, so you get an error. You need to initialize the value at array[index] if you want to use the << operator.

I am assuming you want an array of arrays, so you can use this instead which will initialize the value at items[index] to an empty array if it is nil before pushing the value onto it

items = []
array.each do |r|
  (items[r.column] ||= []) << r
end

The only change here is that, if items[r.column] returns nil it will be set equal to an empty array, otherwise nothing will be done. If you really just want to set the value at items[index] to r, just use the = operator.

Upvotes: 1

Related Questions