am trying to read the files of months for a year. In files there are some empty values.
am trying to compare value of array (which i read from file) with default value but i keep getting the following error:
undefined method `>' for [1000, []]:Array (NoMethodError)
i checked the class of value which am getting from file it's integer but why then it's showing this error
def monthly_temperature(file_data)
highest_temp = max_humdity = 0
lowest_temp = 100 , info = []
array = file_data.map { |string| string.split(',') }
array.each_with_index do |days, ind|
array[ind].shift() #removing every first index
if highest_temp < array[ind].first.to_i
highest_temp = array[ind].first.to_i
end
a = array[ind].fetch(2).to_i
#puts a.class
if lowest_temp > a
lowest_temp = a
end
end
end
Your javascript-like assignment:
lowest_temp = 100 , info = []
is equivalent to
lowest_temp = [100, info = []]
resulting lowest_temp holding an array. Correct parallel assignment is done like this:
lowest_temp, info = 100, []
Generally it should be only used when destructuring an array or when assigned values have a similar meaning (and assigning them together makes code easier to understand). In all the other cases, regular assignment is preferable for readability:
lowest_temp = 100
info = []
Related
I'm trying to write quicksort in Ruby, but I get an error that says:
qsort.rb:43:in `<': comparison of Fixnum with nil failed (ArgumentError)
from qsort.rb:43:in `block in dist'
from qsort.rb:42:in `each'
from qsort.rb:42:in `dist'
from qsort.rb:32:in `sort'
from qsort.rb:34:in `sort'
from qsort.rb:53:in `<main>'
This is my code:
#!usr/bin/ruby
class QArray
#data = []
#pvalue
#less
#more
def initialize(arr = [])
#data = arr
#pvalue = #data[0] unless #data.empty?
end
#these methods are so I can treat a QArray like a regular array
def push(value)
#data.push value
end
def empty?
#data.empty?
end
def single?
return #data.size == 1
end
def print
puts #data
end
def sort
puts "starting the sort with an array of #{#data}"
dist unless #data.empty?
#less.sort unless #less.empty? || #less.single?
#more.sort unless #more.empty? || #more.single?
#data = #less + #more #combine the two arrays again
end
def dist
#distributes values into subarrays
#less = QArray.new
#more = QArray.new
#data.each {|e|
if (e < #pvalue)
#less.push e
else #includes both equals and greater than
#more.push e
end
}
end
end
arr = QArray.new ([1,5,6,7,9,23,43,2,4,6])
arr.sort
arr.print
I'm guessing that this is related to e being nil in the block. However, this shouldn't happen, because I check whether the array is empty before I call dist.
Why do I get this error, and what can I do to fix it?
You create new QArrays in dist.
You initialize #pvalue on QArray creation, but they're empty when created in dist.
In dist you then try to use #pvalue, which is nil, because you create the array empty and only then add values to it, never updating the uninitialized #pvalue value.
Unrelated, but what are those class instance variables at the top of QArray for?!
I am trying to write a small function with ruby that gets fed a array from the user and then sums up the data in the array. I have written it as
def sum(a)
total = 0
a.collect { |a| a.to_i + total }
end
The function then runs through a rspec, which tests it by initially feeding into it a blank array. This this causes the following error
sum computes the sum of an empty array
Failure/Error: sum([]).should == 0
expected: 0
got: [] (using ==)
So its telling me that when it feeds the blank array in, its supposed to get 0 but instead its getting the array. I tried putting in a if statement written as
def sum(a)
total = 0
a.collect { |a| a.to_i + total }
if total = [] then { total = 0 end }
end
but it gives me an error saying
syntax error, unexpected '}', expecting => (SyntaxError)
what am I doing wrong?
You shouldn't use map/collect for this. reduce/inject is the appropriate method
def sum(a)
a.reduce(:+)
# or full form
# a.reduce {|memo, el| memo + el }
# or, if your elements can be strings
# a.map(&:to_i).reduce(:+)
end
See here: How to sum array of numbers in Ruby?
and here: http://www.ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject
def sum(a)
array.inject(0) {|sum,x| sum + x.to_i }
end
gets.split.map(&:to_i).inject(:+)
I'm trying to create some arrays in some threads and name them after a fixnum between 1 and 30 like the following:
times = 30
n=0
thread = []
while n < times
thread << Thread.new(n) {|x|
array#{x} = Array.new()
...
}
end
How can I do that?
Ruby does not allow you to create variable names from strings in the same way that PHP does. In a case such as this you could use an array or a hash instead.
times = 30
n=0
arrays = []
thread = []
while n < times
thread << Thread.new(n) {|x|
arrays[x] = Array.new()
...
}
end
You can also use more rubyish constructs instead of while, such as Fixnum#times.
arrays = []
threads = 30.times.map do |n|
Thread.new do
arrays[x] = Array.new
# ...
end
end
> arrays
#=> [[], [], [], ....]
> threads
#=> [#<Thread:0x007fe3f22a2320 dead>, #<Thread:0x007fe3f22a2208 dead>, ...]
If you don't mind using instance variables rather than local variables, you can do what you are trying to do (whether it is a good idea to design code in this way is another question).
1.upto(times) do |i|
instance_variable_set("#array#{i}".to_sym, [])
end
Edit: The issue is being unable to get the quantity of arrays within the hash, so it can be, x = amount of arrays. so it can be used as function.each_index{|x| code }
Trying to use the index of the amount of rows as a way of repeating an action X amount of times depending on how much data is pulled from a CSV file.
Terminal issued
=> Can't convert symbol to integer (TypeError)
Complete error:
=> ~/home/tests/Product.rb:30:in '[]' can't convert symbol into integer (TypeError) from ~home/tests/Product.rub:30:in 'getNumbRel'
from test.rb:36:in '<main>'
the function is that is performing the action is:
def getNumRel
if defined? #releaseHashTable
return #releaseHashTable[:releasename].length
else
#releaseHashTable = readReleaseCSV()
return #releaseHashTable[:releasename].length
end
end
The csv data pull is just a hash of arrays, nothing snazzy.
def readReleaseCSV()
$log.info("Method "+"#{self.class.name}"+"."+"#{__method__}"+" has started")
$log.debug("reading product csv file")
# Create a Hash where the default is an empty Array
result = Array.new
csvPath = "#{File.dirname(__FILE__)}"+"/../../data/addingProdRelProjIterTestSuite/releaseCSVdata.csv"
CSV.foreach(csvPath, :headers => true, :header_converters => :symbol) do |row|
row.each do |column, value|
if "#{column}" == "prodid"
proHash = Hash.new { |h, k| h[k] = [ ] }
proHash['relid'] << row[:relid]
proHash['releasename'] << row[:releasename]
proHash['inheritcomponents'] << row[:inheritcomponents]
productId = Integer(value)
if result[productId] == nil
result[productId] = Array.new
end
result[productId][result[productId].length] = proHash
end
end
end
$log.info("Method "+"#{self.class.name}"+"."+"#{__method__}"+" has finished")
#productReleaseArr = result
end
Sorry, couldn't resist, cleaned up your method.
# empty brackets unnecessary, no uppercase in method names
def read_release_csv
# you don't need + here
$log.info("Method #{self.class.name}.#{__method__} has started")
$log.debug("reading product csv file")
# you're returning this array. It is not a hash. [] is preferred over Array.new
result = []
csvPath = "#{File.dirname(__FILE__)}/../../data/addingProdRelProjIterTestSuite/releaseCSVdata.csv"
CSV.foreach(csvPath, :headers => true, :header_converters => :symbol) do |row|
row.each do |column, value|
# to_s is preferred
if column.to_s == "prodid"
proHash = Hash.new { |h, k| h[k] = [ ] }
proHash['relid'] << row[:relid]
proHash['releasename'] << row[:releasename]
proHash['inheritcomponents'] << row[:inheritcomponents]
# to_i is preferred
productId = value.to_i
# this notation is preferred
result[productId] ||= []
# this is identical to what you did and more readable
result[productId] << proHash
end
end
end
$log.info("Method #{self.class.name}.#{__method__} has finished")
#productReleaseArr = result
end
You haven't given much to go on, but it appears that #releaseHashTable contains an Array, not a Hash.
Update: Based on the implementation you posted, you can see that productId is an integer and that the return value of readReleaseCSV() is an array.
In order to get the releasename you want, you have to do this:
#releaseHashTable[productId][n][:releasename]
where productId and n are integers. Either you'll have to specify them specifically, or (if you don't know n) you'll have to introduce a loop to collect all the releasenames for all the products of a particular productId.
This is what Mark Thomas meant:
> a = [1,2,3] # => [1, 2, 3]
> a[:sym]
TypeError: can't convert Symbol into Integer
# here starts the backstrace
from (irb):2:in `[]'
from (irb):2
An Array is only accessible by an index like so a[1] this fetches the second element from the array
Your return a an array and thats why your code fails:
#....
result = Array.new
#....
#productReleaseArr = result
# and then later on you call
#releaseHashTable = readReleaseCSV()
#releaseHashTable[:releasename] # which gives you TypeError: can't convert Symbol into Integer
I want a twodimensional array in Ruby, that I can access for example like this:
if #array[x][y] == "1" then #array[x][y] = "0"
The problem is: I don't know the initial sizes of the array dimensions and i grow the array (with the << operator).
How do I declare it as an instance variable, so I get no error like this?
undefined method `[]' for nil:NilClass (NoMethodError)
QUESTION UPDATED:
#array = Array.new {Array.new}
now works for me, so the comment from Matt below is correct!
I just found out the reason why I received the error was because I iterated over the array like this:
for i in 0..#array.length
for j in 0..#array[0].length
#array[i][j] ...
which was obviously wrong and produced the error. It has to be like this:
for i in 0..#array.length-1
for j in 0..#array[0].length-1
#array[i][j] ...
A simple implementation for a sparse 2-dimensional array using nested Hashes,
class SparseArray
attr_reader :hash
def initialize
#hash = {}
end
def [](key)
hash[key] ||= {}
end
def rows
hash.length
end
alias_method :length, :rows
end
Usage:
sparse_array = SparseArray.new
sparse_array[1][2] = 3
sparse_array[1][2] #=> 3
p sparse_array.hash
#=> {1=>{2=>3}}
#
# dimensions
#
sparse_array.length #=> 1
sparse_array.rows #=> 1
sparse_array[0].length #=> 0
sparse_array[1].length #=> 1
Matt's comment on your question is totally correct. However, based on the fact that you've tagged this "conways-game-of-life", it looks like you are trying to initialize a two dimensional array and then use this in calculations for the game. If you wanted to do this in Ruby, one way to do this would be:
a = Array.new(my_x_size) { |i| Array.new(my_y_size) { |i| 0 }}
which will create a my_x_size * my_y_size array filled with zeros.
What this code does is to create a new Array of your x size, then initialize each element of that array to be another Array of your y size, and initialize each element of each second array with 0's.
Ruby's Array doesn't give you this functionality.
Either you manually do it:
(#array[x] ||= [])[y] = 42
Or you use hashes:
#hash = Hash.new{|h, k| h[k] = []}
#hash[42][3] = 42
#hash # => {42 => [nil, nil, nil, 42]}