I'm trying to take a bunch of number-word pairs and group the words according to common numbers. I can match the numbers, merge the subarrays that share the number, and erase the first of those subarrays. But when I try to delete the second, I get this error:
"in block in <main>': undefined method
[]' for nil:NilClass (NoMethodError)"
The guilty line -- ary.delete_at(i+1) -- has been commented out. Secondary problem: MRBTree is not taking the nested arrays as input...
ary = [[2.28, "cat"], [2.28, "bat"], [2.327, "bear"], [2.68, "ant"], [2.68, "anu"]]
i = 0
for i in 0 ... ary.size - 1
if ary[i][0] == ary[i+1][0]
b = (ary[i]+ary[i+1]).uniq
ary.delete_at(i)
# ary.delete_at(i+1)
c = [b.first], b.pop(b.length - 1)
h = Hash[*c]
ary.push(*h)
# mrbtree = MultiRBTree[c]
end
end
puts ary.inspect
output:
# => [
# => [2.28, "bat"],
# => [2.327, "bear"],
# => [2.68, "anu"],
# => [
# => [2.28], ["cat", "bat"]
# => ],
# => [
# => [2.68], ["ant", "anu"]
# => ]
# => ]
Any help appreciated!
Your attempt is failing because you are modifying the array (which has impact on a.size
) in the loop. The loop end condition is not adjusted automagically. You are accessing things you have deleted before.
If your array is not too big, this will do:
p Hash[ary.group_by(&:first).map { | k, v | [k, v.map(&:last)] }]
# => {2.28=>["cat", "bat"], 2.327=>["bear"], 2.68=>["ant", "anu"]}
It works this way:
ary.group_by(&:first) # group the 2-elem arrays by the number, creating a hash
# like {2.28=>[[2.28, "cat"], [2.28, "bat"]], ...}
.map { | k, v | ... } # change the array of key-value pairs to
[k, v.map(&:last)] # pairs where the value-array contains just the strings
Hash[ ... ] # make the whole thing a hash again
Creating an intermediate array and transferring it back to a hash is some overhead. If this turns out to be an issue, something like this might be better:
h = Hash.new { | a, k | a[k] = [] } # a hash with [] as default value
p ary.inject(h) { | a, (k, v) | a[k] << v; a }