What I expect my code to do:
print out
{ "pivot0"=>5, "left0"=>[5,0,1,2,3,4], "right0"=>[6,7,8,9] }
What my code does: print out { "pivot0"=>5}
I've used print to try to debug. Both hash["left0"] and hash["right0"] return [0,1,2,3,4,6,7,8,9]. Yet neither keys are showing up at all inside hash. And even if they did show up, they don't have the right numbers in them. What am I not understanding? As you can tell by the title, I don't even know what is causing the problem. Trying to write similar code with any one of those factors removed (if, hash, block, or push) seems to give me expected results, so I'm thoroughly confused.
source = [5,0,1,2,3,4,6,7,8,9]
hash = Hash.new([])
l=0
hash['pivot' + l.to_s] = source[0]
source.each_with_index do |e, i|
if i > 0
if e <= hash['pivot' + l.to_s]
puts "hit left on #{e}"
hash['left'+l.to_s] << e
else
puts "hit right on #{e}"
hash['right'+l.to_s] << e
end
end
end
print hash
Problem is the way you are constructing your hash object, and assuming that default value of empty array will be automatically assigned to a key on first access.
As the documentation mentions,
If obj is specified, this single object will be used for all default
values
In your case, the statement like below
hash['left'+l.to_s] << e
is effectively below code:
an_array = hash['left'+l.to_s]
an_array << e
This is not what you might have intended. You need to explicitly update the key's value in hash.
As you update a temporary array, its value is never inserted into hash.
You should be doing:
hash['left'+l.to_s] = hash['left'+l.to_s] << e
Or Alternatively, you can use constructor like below and you should get desired output with rest of code unchanged.
hash = Hash.new {|hash, key| hash[key] = [] }
Here, whenever a key is accessed for first time and it has no value associated with it, then the block {|hash, key| hash[key] = [] } will be executed - which basically assign an empty array value for that key.
Or you could use simple hash initialiser {} and handle nil values, as shown below:
source = [5,0,1,2,3,4,6,7,8,9]
hash = {}
l = 0
hash['pivot' + l.to_s] = source[0]
source.each_with_index do |e, i|
if i > 0
if e <= hash['pivot' + l.to_s]
hash['left'+l.to_s] = (hash['left'+l.to_s] || []) << e
else
hash['right'+l.to_s] = (hash['right'+l.to_s] || []) << e
end
end
end
print hash
#=> {"pivot0"=>5, "left0"=>[0, 1, 2, 3, 4], "right0"=>[6, 7, 8, 9]}
Expression like (hash['left'+l.to_s] || []) returns first operand if its not nil, else returns the value of second operand, which in this case happens to be an empty array.
Just out of curiosity:
src = [5,0,1,2,3,4,6,7,8,9]
%i(pivot left right).zip(
[pivot = src.first, *src.partition { |e| e <= pivot }]
).to_h
#⇒ "{:pivot=>5, :left=>[5, 0, 1, 2, 3, 4], :right=>[6, 7, 8, 9]}"
Related
I've been practicing some algorithms with ruby for a while, and I'm wondering if it is possible to catch the returned value from within the method.
the code below is to reverse a string without any kind of reverse method and with few local variables...
def rev(a)
i = -1
a.split("").each do |el|
el[0] = a[i]
i = i + (-1)
end.join
end
Note that the result of the 'each' method is not being assigned to any variable. So, 'each' evaluates to an array with a reversed sequence of characters. At the 'end' (literally) I've just 'called' the method 'join' to glue everything together. The idea is to 'catch' the returned value from all this process and check if is true or false that the reversed string is a palindrome.
If the reversed string is equal to the original one then the word is a palindrome. Ex. "abba", "sexes", "radar"...
for example:
def rev(a)
i = -1
a.split("").each do |el|
el[0] = a[i]
i = i + (-1)
end.join
# catch here the returned value from the code above
# and check if its a palindrome or not. (true or false)
end
Thank you guys! I will be very grateful if anyone could help me figure out this!
Just add == a to see if your reversal matches the original string:
def rev(a)
i = -1
a.split("").each do |el|
el[0] = a[i]
i = i + (-1)
end.join == a
end
puts rev("racecar") # => true
puts rev("racecars") # => false
An easier way to check palindromes (rev could be better named palindrome?) is a == a.reverse since .reverse is essentially what your split/each/join does.
If you want back all the information, you can return an array with both the values:
def rev(a)
i = -1
rev = a.split("").each do |el|
el[0] = a[i]
i = i + (-1)
end.join
[rev, rev == a] # or
# return rev, rev == a
end
p rev("abra") #=> ["arba", false]
p rev("abba") #=> ["abba", true]
You can also return a hash:
{ reverse: rev, palindrome: rev == a}
to get
#=> {:reverse=>"arba", :palindrome=>false}
#=> {:reverse=>"abba", :palindrome=>true}
Here are a couple of other ways you could reverse a string.
#1
def esrever(str)
s = str.dup
(str.size/2).times { |i| s[i], s[-1-i] = s[-1-i], s[i] }
s
end
esrever("abcdefg")
#=> "gfedcba"
esrever("racecar")
#=> "racecar"
This uses parallel assignment (sometimes called multiple assignment).
#2
def esrever(str)
a = str.chars
''.tap { |s| str.size.times { s << a.pop } }
end
esrever("abcdefg")
#=> "gfedcba"
esrever("racecar")
#=> "racecar"
I've used Object#tap merely to avoid creating a local variable initialized to an empty string and then having to make that variable the last line of the method.
With both methods a string str is a palindrome if and only if str == esrever(str).
If I have a string like this
str =<<END
7312357006,1.121
3214058234,3456
7312357006,1234
1324958723,232.1
3214058234,43.2
3214173443,234.1
6134513494,23.2
7312357006,11.1
END
If a number in the first value shows up again, I want to add their second values together. So the final string would look like this
7312357006,1246.221
3214058234,3499.2
1324958723,232.1
3214173443,234.1
6134513494,23.2
If the final output is an array that's fine too.
There are lots of ways to do this in Ruby. One particularly terse way is to use String#scan:
str = <<END
7312357006,1.121
3214058234,3456
7312357006,1234
1324958723,232.1
3214058234,43.2
3214173443,234.1
6134513494,23.2
7312357006,11.1
END
data = Hash.new(0)
str.scan(/(\d+),([\d.]+)/) {|k,v| data[k] += v.to_f }
p data
# => { "7312357006" => 1246.221,
# "3214058234" => 3499.2,
# "1324958723" => 232.1,
# "3214173443" => 234.1,
# "6134513494" => 23.2 }
This uses the regular expression /(\d+),([\d.]+)/ to extract the two values from each line. The block is called with each pair as arguments, which are then merged into the hash.
This could also be written as a single expression using each_with_object:
data = str.scan(/(\d+),([\d.]+)/)
.each_with_object(Hash.new(0)) {|(k,v), hsh| hsh[k] += v.to_f }
# => (same as above)
There are likewise many ways to print the result, but here are a couple I like:
puts data.map {|kv| kv.join(",") }.join("\n")
# => 7312357006,1246.221
# 3214058234,3499.2
# 1324958723,232.1
# 3214173443,234.1
# 6134513494,23.2
# or:
puts data.map {|k,v| "#{k},#{v}\n" }.join
# => (same as above)
You can see all of these in action on repl.it.
Edit: Although I don't recommend either of these for the sake of readability, here's more just for kicks (requires Ruby 2.4+):
data = str.lines.group_by {|s| s.slice!(/(\d+),/); $1 }
.transform_values {|a| a.sum(&:to_f) }
...or, to going straight to a string:
puts str.lines.group_by {|s| s.slice!(/(\d+),/); $1 }
.map {|k,vs| "#{k},#{vs.sum(&:to_f)}\n" }.join
Since repl.it is stuck on Ruby 2.3: Try it online!
You could achieve this using each_with_object, as below:
str = "7312357006,1.121
3214058234,3456
7312357006,1234
1324958723,232.1
3214058234,43.2
3214173443,234.1
6134513494,23.2
7312357006,11.1"
# convert the string into nested pairs of floats
# to briefly summarise the steps: split entries by newline, strip whitespace, split by comma, convert to floats
arr = str.split("\n").map(&:strip).map { |el| el.split(",").map(&:to_f) }
result = arr.each_with_object(Hash.new(0)) do |el, hash|
hash[el.first] += el.last
end
# => {7312357006.0=>1246.221, 3214058234.0=>3499.2, 1324958723.0=>232.1, 3214173443.0=>234.1, 6134513494.0=>23.2}
# You can then call `to_a` on result if you want:
result.to_a
# => [[7312357006.0, 1246.221], [3214058234.0, 3499.2], [1324958723.0, 232.1], [3214173443.0, 234.1], [6134513494.0, 23.2]]
each_with_object iterates through each pair of data, providing them with access to an accumulator (in this the hash). By following this approach, we can add each entry to the hash, and add together the totals if they appear more than once.
Hope that helps - let me know if you've any questions.
def combine(str)
str.each_line.with_object(Hash.new(0)) do |s,h|
k,v = s.split(',')
h.update(k=>v.to_f) { |k,o,n| o+n }
end.reduce('') { |s,kv_pair| s << "%s,%g\n" % kv_pair }
end
puts combine str
7312357006,1246.22
3214058234,3499.2
1324958723,232.1
3214173443,234.1
6134513494,23.2
Notes:
using String#each_line is preferable to str.split("\n") as the former returns an enumerator whereas the latter returns a temporary array. Each element generated by the enumerator is line of str that (unlike the elements of str.split("\n")) ends with a newline character, but that is of no concern.
see Hash::new, specifically when a default value (here 0) is used. If a hash has been defined h = Hash.new(0) and h does not have a key k, h[k] returns the default value, zero (h is not changed). When Ruby encounters the expression h[k] += 1, the first thing she does is expand it to h[k] = h[k] + 1. If h has been defined with a default value of zero, and h does not have a key k, h[k] on the right of the equality (syntactic sugar1 for h.[](k)) returns zero.
see Hash#update (aka merge!). h.update(k=>v.to_f) is syntactic sugar for h.update({ k=>v.to_f })
see Kernel#sprint for explanations of the formatting directives %s and %g.
the receiver for the expression reduce('') { |s,kv_pair| s << "%s,%g\n" % kv_pair } (in the penultimate line), is the following hash.
{"7312357006"=>1246.221, "3214058234"=>3499.2, "1324958723"=>232.1,
"3214173443"=>234.1, "6134513494"=>23.2}
1 Syntactic sugar is a shortcut allowed by Ruby.
Implemented this solution as hash was giving me issues:
d = []
s.split("\n").each do |line|
x = 0
q = 0
dup = false
line.split(",").each do |data|
if x == 0 and d.include? data then dup = true ; q = d.index(data) elsif x == 0 then d << data end
if x == 1 and dup == false then d << data end
if x == 1 and dup == true then d[q+1] = "#{'%.2f' % (d[q+1].to_f + data.to_f).to_s}" end
if x == 2 and dup == false then d << data end
x += 1
end
end
x = 0
s = ""
d.each do |val|
if x == 0 then s << "#{val}," end
if x == 1 then s << "#{val}\n ; x = 0" end
x += 1
end
puts(s)
I have built a version of mastermind that checks a user's input and provides feedback based on how close the user's guess was to the winning sequence. If you're not familiar with the game, you get feedback indicating how many of your characters were guessed correctly at the same index and how many characters guessed are in the sequence, but at the wrong index. If there are duplicates in the guess, then you would not count the extra values unless they correspond to the same number of duplicates in the secret code.
Example: If the sequence is ["G","G","G","Y"] and the user guesses ["G", "Y","G","G"] then you'd want to return 2 for items at the same index and 2 for items at different indexes that are included in the secret sequence.
Another example: If the sequence is ["X","R","Y","T"] and the user guesses ["T","T","Y","Y"] then you'd return 1 for items at the same index 1 for the character guessed that is in the sequence but at the wrong index.
Anyway, to me this is not a simple problem to solve. Here's the code I used to get it to work, but it's not elegant. There must be a better way. I was hoping someone can tell me what I'm missing here?? New to Ruby...
def index_checker(input_array, sequence_array)
count = 0
leftover_input = []
leftover_sequence = []
input.each_with_index do |char, idx|
if char == sequence[idx]
count += 1
else
leftover_input << char
leftover_sequence << sequence[idx]
end
end
diff_index_checker(leftover_input, leftover_sequence, count)
end
def diff_index_checker(input, sequence, count)
count2 = 0
already_counted = []
input.each do |char|
if sequence.include?(char) && !already_counted.include?(char)
count2 += 1
already_counted << char
end
end
[count, count2]
end
Here's a clean Ruby solution, written in idiomatic Ruby object-oriented style:
class Mastermind
def initialize(input_array, sequence_array)
#input_array = input_array
#sequence_array = sequence_array
end
def matches
[index_matches, other_matches]
end
def results
[index_matches.size, other_matches.size]
end
private
attr_reader :input_array, :sequence_array
def index_matches
input_array.select.with_index { |e, i| e == sequence_array[i] }
end
def other_matches
non_exact_input & non_exact_sequence
end
def non_exact_input
array_difference(input_array, index_matches)
end
def non_exact_sequence
array_difference(sequence_array, index_matches)
end
# This method is based on https://stackoverflow.com/a/3852809/5961578
def array_difference(array_1, array_2)
counts = array_2.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
array_1.reject { |e| counts[e] -= 1 unless counts[e].zero? }
end
end
You would use this class as follows:
>> input_array = ["G","G","G","Y"]
>> sequence_array = ["G", "Y","G","G"]
>> guess = Mastermind.new(input_array, sequence_array)
>> guess.results
#> [2, 2]
>> guess.matches
#> [["G", "G"], ["G", "Y"]]
Here's how it works. First everything goes into a class called Mastermind. We create a constructor for the class (which in Ruby is a method called initialize) and we have it accept two arguments: input array (the user guess), and sequence array (the answer).
We set each of these arguments to an instance variable, which is indicated by its beginning with #. Then we use attr_reader to create getter methods for #input_array and #sequence_array, which allows us to get the values by calling input_array and sequence_array from any instance method within the class.
We then define two public methods: matches (which returns an array of exact matches and an array of other matches (the ones that match but at the wrong index), and results (which returns a count of each of these two arrays).
Now, within the private portion of our class, we can define the guts of the logic. Each method has a specific job, and each is named to (hopefully) help a reader understand what it is doing.
index_matches returns a subset of the input_array whose elements match the sequence_array exactly.
other_matches returns a subset of the input_array whose elements do not match the sequence_array exactly, but do match at the wrong index.
other_matches relies on non_exact_input and non_exact_sequence, each of which is computed using the array_difference method, which I copied from another SO answer. (There is no convenient Ruby method that allows us to subtract one array from another without deleting duplicates).
Code
def matches(hidden, guess)
indices_wo_match = hidden.each_index.reject { |i| hidden[i] == guess[i] }
hidden_counts = counting_hash(hidden.values_at *indices_wo_match)
guess_counts = counting_hash(guess.values_at *indices_wo_match)
[hidden.size - indices_wo_match.size, guess_counts.reduce(0) { |tot, (k, cnt)|
tot + [hidden_counts[k], cnt].min }]
end
def counting_hash(arr)
arr.each_with_object(Hash.new(0)) { |s, h| h[s] += 1 }
end
Examples
matches ["G","G","G","Y"], ["G", "Y","G","G"]
#=> [2, 2]
matches ["X","R","Y","T"] , ["T","T","Y","Y"]
#=> [1, 1]
Explanation
The steps are as follows.
hidden = ["G","G","G","Y"]
guess = ["G", "Y","G","G"]
Save the indices i for which hidden[i] != guess[i].
indices_wo_match = hidden.each_index.reject { |i| hidden[i] == guess[i] }
#=> [1, 3]
Note that the number of indices for which the values are equal is as follows.
hidden.size - indices_wo_match.size
#=> 2
Now compute the numbers of remaining elements of guess that pair with one of the remaining values of hidden by having the same value. Begin by counting the numbers of instances of each unique element of hidden and then do the same for guess.
hidden_counts = counting_hash(hidden.values_at *indices_wo_match)
#=> {"G"=>1, "Y"=>1}
guess_counts = counting_hash(guess.values_at *indices_wo_match)
#=> {"Y"=>1, "G"=>1}
To understand how counting_hash works, see Hash::new, especially the explanation of the effect of providing a default value as an argument of new. In brief, if a hash is defined h = Hash.new(3), then if h does not have a key k, h[k] returns the default value, here 3 (the hash is not changed).
Now compute the numbers of matches of elements of guess that were not equal to the value of hidden at the same index and which pair with an element of hidden that have the same value.
val_matches = guess_counts.reduce(0) do |tot, (k, cnt)|
tot + [hidden_counts[k], cnt].min
end
#=> 2
Lastly, return the values of interest.
[hidden.size - indices_wo_match.size, val_matches]
#=> [2, 2]
In the code presented above I have substituted out the variable val_matches.
With Ruby 2.4+ one can use Enumerable#sum to replace
guess_counts.reduce(0) { |tot, (k, cnt)| tot + [hidden_counts[k], cnt].min }
with
guess_counts.sum { |k, cnt| [hidden_counts[k], cnt].min }
def judge(secret, guess)
full = secret.zip(guess).count { |s, g| s == g }
semi = secret.uniq.sum { |s| [secret.count(s), guess.count(s)].min } - full
[full, semi]
end
Demo:
> judge(["G","G","G","Y"], ["G","Y","G","G"])
=> [2, 2]
> judge(["X","R","Y","T"], ["T","T","Y","Y"])
=> [1, 1]
A shorter alternative, though I find it less clear:
full = secret.zip(guess).count(&:uniq!)
I prefer my other answer for its simplicity, but this one would be faster if someone wanted to use this for arrays larger than Mastermind's.
def judge(secret, guess)
full = secret.zip(guess).count { |s, g| s == g }
pool = secret.group_by(&:itself)
[full, guess.count { |g| pool[g]&.pop } - full]
end
Demo:
> judge(["G","G","G","Y"], ["G","Y","G","G"])
=> [2, 2]
> judge(["X","R","Y","T"], ["T","T","Y","Y"])
=> [1, 1]
so I'm doing the Learn Ruby the Hard Way exercises and got stuck on one line. Tried googling and even looking for answers in the Python lessons. But Couldnt find an answer.
My question is: Why does Dict.get_slot have this line(what is it for?): return -1, key, default
The original exercise is here: http://ruby.learncodethehardway.org/book/ex39.html
Thanks guys/gals!
module Dict
def Dict.new(num_buckets=256)
# Initializes a Dict with the given number of buckets.
aDict = []
(0...num_buckets).each do |i|
aDict.push([])
end
return aDict
end
def Dict.hash_key(aDict, key)
# Given a key this will create a number and then convert it to
# an index for the aDict's buckets.
return key.hash % aDict.length
end
def Dict.get_bucket(aDict, key)
# Given a key, find the bucket where it would go.
bucket_id = Dict.hash_key(aDict, key)
return aDict[bucket_id]
end
def Dict.get_slot(aDict, key, default=nil)
# Returns the index, key, and value of a slot found in a bucket.
bucket = Dict.get_bucket(aDict, key)
bucket.each_with_index do |kv, i|
k, v = kv
if key == k
return i, k, v
end
end
return -1, key, default
end
def Dict.get(aDict, key, default=nil)
# Gets the value in a bucket for the given key, or the default.
i, k, v = Dict.get_slot(aDict, key, default=default)
return v
end
def Dict.set(aDict, key, value)
# Sets the key to the value, replacing any existing value.
bucket = Dict.get_bucket(aDict, key)
i, k, v = Dict.get_slot(aDict, key)
if i >= 0
bucket[i] = [key, value]
else
bucket.push([key, value])
end
end
def Dict.delete(aDict, key)
# Deletes the given key from the Dict.
bucket = Dict.get_bucket(aDict, key)
(0...bucket.length).each do |i|
k, v = bucket[i]
if key == k
bucket.delete_at(i)
break
end
end
end
def Dict.list(aDict)
# Prints out what's in the Dict.
aDict.each do |bucket|
if bucket
bucket.each {|k, v| puts k, v}
end
end
end
end
Why does Dict.get_slot have this line(what is it for?): return -1, key, default
That is a return statement that returns an array of three values. Before executing the return statement, ruby will substitute in the values for the variables key and default, then ruby will gather the three values into an Array and return the array. Here is an example:
def dostuff
key = 'a'
default = 10
return -1, key, default
end
p dostuff
--output:--
[-1, "a", 10]
As the comment says:
# Returns the index, key, and value of a slot found in a bucket.
Response to comment:
A Dict is an array of arrays, e.g.:
[
[200, 'hello'],
[210, 'world'],
]
The first element of the array is an Integer that the real key has been converted to, and the second element is the value.
Dict.get_slot() has two possible return values:
bucket.each_with_index do |kv, i|
k, v = kv
if key == k
return i, k, v #****HERE*****
end
end
return -1, key, default #*****OR HERE****
If the key is found in the Dict, which means the key is equal to the first element of one of the sub arrays, then the first return statement executes, and the index of the subarray is returned along with the elements of the subarray, i.e the key and value. The second return statement doesn't execute.
If the key is not found in the Dict, then the first return statement is skipped and the second return statement executes. In the second return statement, -1 is returned for the index of the subarray. The code could have been written to return nil instead, but in other languages it is common to return -1 when a search does not find an element in an array; you know from the documentation for that method that if the index value is -1, then the search came up empty. The docs would say something like:
Dict.get_slot(): returns a three element array. The first element of the
returned array is the index of the subarray containing the key
or -1 if no subarray contains the key...
As for the default, ruby Hashes allow you to specify a default value that is returned when you try to retrieve a non-existent key(other languages also provide that feature). That allows you to do things like this:
h = Hash.new(0)
h['a'] = 1
h['b'] = 2
target_keys = %w[a b c] #=>['a', 'b', 'c'] For people who are too lazy to type all those quote marks.
sum = 0
target_keys.each do |target_key|
sum += h[target_key]
end
puts sum #=>3
If you couldn't specify a default value, then nil would be returned when a non-existent key was looked up in the Hash, and this would be the result:
`+': nil can't be coerced into Fixnum (TypeError)
That's because the code tries to add nil into the sum. Of course, you could work around that by testing if h[target_key] is nil before doing the addition, but being able to specify a default makes the code more succinct.
Another default example that is more useful and is very common:
results = Hash.new { |this_hash, key| this_hash[key] = [] }
data = [
['a', 1],
['b', 2],
['a', 3],
['b', 4],
['c', 5],
]
data.each do |(key, val)| #The parentheses cause the the subarray that is passed to the block to be exploded into its individual elements and assigned to the variables.
results[key] << val
end
p results
--output:--
{"a"=>[1, 3], "b"=>[2, 4], "c"=>[5]}
If you couldn't specify a default value, then the following line would cause an error:
results[key] << val
When the key didn't exist in the hash yet, results[key] would return nil, and you can't shove val into nil. Once again, you could work around that by testing for nil and then creating a new key whose value is a new array, and then shoving val into the new array.
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!
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.
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.
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 }