pushing a value into an array within a hash - arrays

Ive been working at this code for a radix sort for awhile now. Everything has seemed to be coming together fine until i try to push a value into an array within a hash.
Im getting an error message that the value is nil, however ive checked all the values in question just prior to trying to store them in the array and its still not allowing me to do so. Any ideas? buckets[sdigit].push(num) is the line that tells me one of my values is nil.
arr = []
while arr.size < 100
arr.push(rand(1000))
end
for outer_index in arr
puts "for outer index(#{outer_index} in arr"
buckets = Hash.new()
puts "buckets = Hash.new()"
puts "for j in 0..9"
for j in 0..9
buckets[j.to_s] = Array.new()
#buckets[j.to_s] = [j]
puts "buckets[j.to_s(#{buckets[j.to_s]})"
end
for inner_index in arr
puts "for inner_index(#{inner_index}) in arr"
num = inner_index
puts "num(#{num}) = inner_index(#{inner_index})"
sdigit = num.to_s[-1]
puts "sdigit(#{sdigit}) = num.to_s[-1](#{num.to_s[-1]})"
digit = sdigit.to_i
puts "digit(#{digit}) = sdigit.to_i(#{sdigit.to_i})"
puts "buckets[digit] = #{buckets[sdigit]}"
puts "#{buckets["1"]}"
puts "o#{num}"
puts buckets
buckets[sdigit].push(num)
puts "buckets[digit].push(num)(#{buckets[digit].push(num)})"
end
arr = buckets.values.flatten
end `

buckets[sdigit].push(num) is the line that tells me one of my values
is nil.
If you look at the error message :
top.rb:30:in `block (2 levels) in <main>': undefined method `push' for nil:NilClass (NoMethodError)
and your code :
you see that line 30 is the puts, not buckets[sdigit].push(num).
Cause : there is a discrepancy between the values displayed by the puts and those used by the expression : [digit] instead of [sdigit], and that's the trace which causes the error.
Personally I write the puts traces before the statement to trace, because it shows the values that will be used by the expression before the statement which could cause the error is executed. It usually helps ... except when the trace itself is in error.
I have slightly rearranged your code :
arr = []
100.times { arr << rand(1000) }
puts arr.join(', ')
arr.each do | outer_index |
puts "===== for outer_index=#{outer_index} in arr"
buckets = Hash.new()
puts "buckets = Hash.new()"
puts "for j in 0..9"
(0..9).each do | j |
buckets[j.to_s] = Array.new()
#buckets[j.to_s] = [j]
puts "buckets[#{j.to_s}]=#{buckets[j.to_s]}"
end
arr.each do | inner_index |
puts "----- for inner_index=#{inner_index} in arr"
num = inner_index
puts "num(#{num}) = inner_index(#{inner_index})"
sdigit = num.to_s[-1]
puts "sdigit(#{sdigit}) = num.to_s[-1](#{num.to_s[-1]})"
digit = sdigit.to_i
puts "digit(#{digit}) = sdigit.to_i(#{sdigit.to_i})"
puts "buckets[digit] = #{buckets[sdigit]}"
puts "#{buckets["1"]}"
puts "o#{num}"
puts buckets
puts "buckets[sdigit].push(num)=buckets[#{sdigit}].push(#{num})"
buckets[sdigit].push(num)
# puts "buckets[digit].push(num)(#{buckets[digit].push(num)})"
end
arr = buckets.values.flatten
end

Related

Changing an element in a multidimensional array doesen't work in Ruby

I made a class that represents a matrix using a multidimensional array. The initialize method goes through every position and sets the value of the elements to the one specified, and the to_s method does the same but it just concatenates every element to a string. I'm writing an insert method that changes the value of the element of a given position to a given value, but it changes a whole value instead of just an element.
class Matrix
attr_accessor :rows, :cols, :arr
# Goes through the matrix setting everything with the "n" value
def initialize(r, c, n = "a")
#rows = r
#cols = c
#arr = Array.new(#rows)
tmpArray = Array.new(#cols)
i = 0
while i < #rows
j = 0
while j < #cols
tmpArray[j] = n
j += 1
end
#arr[i] = tmpArray
i += 1
end
return #arr
end
def to_s
i = 0
str = String.new
while i < #rows
j = 0
str << "("
while j < #cols
str << " "
if #arr[i][j].is_a?String
str << #arr[i][j]
else
str << #arr[i][j].to_s
end
j += 1
end
str << " )\n"
i += 1
end
return str
end
# Calls and prints to_s
def write
print self.to_s
return self.to_s
end
# Rewrites the element (r, c) as the value in "n"
def insert(r, c, n)
#arr[r][c] = n
self.write
return self
end
end
The thing is that, when I print the matrix I notice that I didn't change just an element, but a whole column of the matrix.
a = Matrix.new(2, 2, 0)
a.insert(0, 0, 1)
a.write
# Expected output: ( 1 0 )
# ( 0 0 )
# Real output: ( 1 0 )
# ( 1 0 )
The to_s method isn't failing. I already made a trace of it and tested it. I'm printing the real values that are in the positions of the matrix.
Your program calls Array.new only twice, and it doesn't create arrays using any other methods, and it doesn't use dup or clone to copy any arrays. Therefore, you only have two different array objects in your program. Each element of #arr actually points to the same row array.
One idea for a solution would be to replace this line:
#arr[i] = tmpArray
with this:
#arr[i] = tmpArray.dup
However, your code is pretty long and I have not tried running it, so I do not know if that would be a complete solution.

I have a problem with 2D arrays in RUBY where it doesn't assign the values into it

PLAYERS = 4
def input(noteam, arraya)
for x in 0..noteam-1
for y in 0..PLAYERS-1
arraya[x] = Array.new(PLAYERS)
puts "Team " + (x+1).to_s
arraya[x][y] = read_integer("Enter score for individual player " + (y+1).to_s)
end
end
end
def disp_arr(myarray, row, col)
print myarray[0]
for x in 0..row-1
for y in 0..col-1
print myarray[x][y]
end
end
end
def main
notm = read_integer("How many teams:")
arraya = Array.new(notm)
input(notm, arraya)
disp_arr(arraya, notm, PLAYERS)
end
main #=> invoking the main method
So I tried doing print myarray[0] for the first row and [nil,nil,nil,10] comes out so I know that there's a problem with assigning the value into the array but I'm not too sure whats wrong with it.
Move line arraya[x] = Array.new(PLAYERS) out of internal for loop
def input(noteam, arraya)
for x in 0..noteam-1
arraya[x] = Array.new(PLAYERS) # <-
puts "Team #{x + 1}"
for y in 0..PLAYERS-1
puts "Player: #{y + 1}"
arraya[x][y] = read_integer("Enter score for individual player " + (y+1).to_s)
end
end
end
Your original code reset arraya[x] to new array for every team player except last.
That is why you observing [nil, nil, nil, 45] result, because only last player results being saved.

Ruby: NoMethodError when comparing element in an array

I'm working on a method that takes an array of words as a param and returns an array of arrays, where each subarray contains words that are anagrams of each other. The line while sort_array[i][1]==temp do is throwing undefined method '[]' for nil:NilClass (NoMethodError) and I have no idea why.
def combine_anagrams(words)
sort_array = Hash.new
words.each do |w|
sort_array[w] = w.split("").sort
end
sort_array = sort_array.sort_by { |w, s| s }
return_array = []
i = 0
while i<sort_array.length do
temp_array = []
temp = sort_array[i][1]
while sort_array[i][1]==temp do
temp_array += [sort_array[i][0]]
i+=1
end
return_array += [temp_array]
end
return temp_array
end
p combine_anagrams( ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams','scream'] )
It looks like this is because you are incrementing your i variable without checking to make sure you're still in bounds of the sort_array. To see the problem, put an puts statement in your code inside the inner most while loop:
while sort_array[i][1]==temp do
temp_array += [sort_array[i][0]]
i+=1
puts "i is #{i} and the length is #{sort_array.length}"
end
and then run your code and you'll see:
i is 1 and the length is 8
i is 2 and the length is 8
i is 3 and the length is 8
i is 4 and the length is 8
i is 5 and the length is 8
i is 6 and the length is 8
i is 7 and the length is 8
i is 8 and the length is 8
example.rb:15:in `combine_anagrams': undefined method `[]' for nil:NilClass (NoMethodError)
You need to make sure on both while loops that you stay within the bounds of your array, for instance:
while i < sort_array.length && sort_array[i][1]==temp do
end
As a side note, your code is currently only going to return the last temp_array, since you're also resetting that at the beginning of your outer while loop. And, if I understand what problem you're trying to solve you might want to look at group_by available on Array thanks to the Enumerable module:
words = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams','scream']
words.group_by { |word| word.chars.sort }.values
# => [["cars", "racs", "scar"], ["for"], ["potatoes"], ["four"], ["creams", "scream"]]

Ruby - Pushing Hash to Array

While iterating, I am saving some data to a hash each time. Within the same loop, I push the hash to an array.
The below code does not work, the last hash object overwrites all the other ones in the array.
playlists = []
aPlaylist = {}
while (count < 3)
#some code... produces the hash "aPlaylist"
playlist << aPlaylist
end
The code below does work. Why, and what is the difference?
playlists = []
while (count < 3)
aPlaylist = {}
#some code... produces the hash "aPlaylist"
playlist << aPlaylist
end
Here are the correct and wrong outputs (converted to csv):
http://imgur.com/a/rjmBA.
Because, in the first case, the object is same that is on 0, 1, and 2nd index.
playlist = []
aPlaylist = {}
count = 0
while (count < 3)
#some code... produces the hash "aPlaylist"
playlist << aPlaylist
puts aPlaylist.object_id
count += 1
end
#=> 2048
#=> 2048
#=> 2048
While in second case it changes:
playlist = []
count = 0
while (count < 3)
aPlaylist = {}
#some code... produces the hash "aPlaylist"
playlist << aPlaylist
puts aPlaylist.object_id
count += 1
end
#=> 2048
#=> 2038
#=> 2028
Which is why from second case when you make changes to hash, it does not get reflected in all places in array.
Read this stackoverflow answer for more detail.
aPlaylist = {} creates a hash and aPlaylist variable holds a pointer to the hash object.
In your first example you edit only this one hash object.
aPlaylist = {}
count = 0
while (count < 3)
puts aPlaylist.object_id
count += 1
end
#=> 70179174789100
#=> 70179174789100
#=> 70179174789100
In your second example you create a new hash object within each iteration. That's way this code works.
count = 0
while (count < 3)
aPlaylist = {}
puts aPlaylist.object_id
count += 1
end
#=> 70179182889040
#=> 70179182888980
#=> 70179182888920
Have a look to the printed object-ids.
I think an idiomatic Ruby approach would be something like ...
playlist = 0.upto(2).map{|count| something_that_returns_a_hash }
... or ...
playlist = (0..2).map{|count| something_that_returns_a_hash }
Hence:
0.upto(2).map{|count| {count => count} }
[{0=>0}, {1=>1}, {2=>2}]

Using Ruby: Why is my array printing the results then an array of with idex numbers

I have two methods:
pwsplayerindex finds a person that is in an array multiple times and gives the index of where their name is.
statarray uses the index # from pwsplayerindex to find other data in an array with hashes.
def pwsplayerindex(inplayer)
arr = Array.new
pwsarr.each_with_index do |val,index|
if val['player'] == inplayer then arr << index end
end
arr
end
def statarray(index,stat)
indexarr = Array.new
pwsplayerindex((pwsarr[index]['player'])).each { |x| puts (pwsarr[x][stat])}
end
print statarray(0,'play')
Why does the result yield:
51.0
29.9
29.4
28.1
24.6
16.6
[0,82,88,113,192,472]
All I want it to give me is:
51.0
29.9
29.4
28.1
24.6
16.6
puts statarray(0,'play')
should be just
statarray(0,'play')
otherwise you print the return value of the function, which is the entire array (because the each method)
This is what I was shooting for:
def pwsplayerindex(inplayer)
arr = []
pwsarr.each_with_index do |val,index|
if val['player'] == inplayer then arr << index end
end
arr
end
def statarray(i,stat)
indexarr = Array.new
pwsplayerindex((pwsarr[i]['player'])).each do |x|
indexarr << pwsarr[x][stat]
end
indexarr
end
puts statarray(0,'play')
This gives me what I was aiming for in my original question. It was a simple fix. I didn't realize I was printing in the method.

Resources