In file1.lua I have something like
require "file2"
outerTable = { ["thing1"] = {"1", "2", "3"}, ["thing2"] = {"4", "5", "6"}}
penultimateThing = callAFunction(outerTable["thing1"])
in file2.lua I have something like
callAFunction(table)
for k,v in ipairs(table) do
print(k, v)
end
end
When I try to pass a nested table like this, it's always nil. What gives?
Maybe another typo, but you are not saying function callAFunction. Without that, I get the error: <eof> expected near end. This means that there is an end where the compiler assumes the file should end. Tracing back we find that we close a for loop and that we want to close the function definition. The function definition, however, is not opened, so cannot be closed either.
Try to change it to:
function callAFunction(table)
for k,v in ipairs(table) do
print(k, v)
end
end
For me, this seems to work
I am trying to group entries in a csv file into different tables in Lua, based on the last attribute. But for some reason the string comparison doesn't work. The following is the code:
trainer = {}
tester = {}
valer = {}
for line in io.lines(mlist) do
local split = {}
for token in string.gmatch(line, '([^,]+)') do
table.insert(split, token)
if token == 'val' then
print('heelo')
end
end
if split[5] == "val" then
print('hello world')
end
if split[5] == 'test' then
table.insert(tester, split[1])
elseif split[5] == 'train' then
table.insert(trainer, split[1])
elseif (split[5] == 'val') then
print('hello')
table.insert(valer, split[1])
end
end
The file mlist contains the following entries (It actually has a lot of records, but I am putting a few for testing):
050810,02747177,02747177,a2e9d8324c1f62cd5ecea499ceee624d,train
051087,02747177,02747177,89aff0d006fc22ff9405d3391cbdb79b,train
051145,02747177,02747177,c6ef918f335bb21c5896bab37ddebe7,train
051416,02747177,02747177,ec1c1aa7003cf68d49e6f7df978f3373,train
051506,02747177,02747177,a8b39c32604173c1d2b12aa6a0f050b3,train
051654,02747177,02747177,e3484284e1f301077d9a3c398c7b4709,train
001174,02747177,02747177,bf4dd114b53bd8f0d67352166d8df9fd,val
003009,02747177,02747177,2f1aed8925147120c62ac18334863d36,val
003735,02747177,02747177,c3b31dc8c48265ecfffc97a61124b1a9,val
004213,02747177,02747177,3a982b20a1c8ebf487b2ae2815c9,val
005241,02747177,02747177,91a4d060d380409c2056b4bd5d870b47,val
008467,02747177,02747177,4d6b6d392ec6b5b4c69692992c7aeb,val
008652,02747177,02747177,3be3e86b2fad511048d5a1386787189,val
008659,02747177,02747177,1e1015a06e43c0a5a44b6af22454453b,val
010510,02747177,02747177,62f4ed6e1df63042cecaed25e0da0964,val
013730,02747177,02747177,7069760a16db98f46c9e5b09a1c294d9,val
016657,02747177,02747177,ae3257e7e0dca9a4fc8569054682bff9,val
018178,02747177,02747177,86194a4645da1f19e14ca01ae177e9d,val
019142,02747177,02747177,e5b7b5112e396a49b581cc9c4410f841,val
021424,02747177,02747177,4088f2056763a95752e986a5f722a6f,val
022098,02747177,02747177,b77e94ab409def2b72745b90f9692729,val
022185,02747177,02747177,b51812771e42354f9996a93ae0c9395c,val
027358,02747177,02747177,5092afb4be0a2f89950ab3eaa7fe7772,val
028916,02747177,02747177,63adebf24a1de9ecf91cc5a18046145f,val
031579,02747177,02747177,1c3cf618a6790f1021c6005997c63924,val
032507,02747177,02747177,dc7ce614dc719649b394cfa64dfabe8e,val
034010,02747177,02747177,6a1b359efc20cd1aaec6ee5ba573fa6d,val
035290,02747177,02747177,c904d927672acd48ad8a0ee9b106700e,val
036604,02747177,02747177,f116f3c432856fccddd8899c86e55073,val
039697,02747177,02747177,c21d8f5641be31a285cac25b72167160,val
040234,02747177,02747177,330cdd681a0890b190fdbeabcd02777c,val
041653,02747177,02747177,b838c5bc5241a44bf2f2371022475a36,val
044825,02747177,02747177,af6fa396b2869446d4d8765e3910f617,val
046115,02747177,02747177,1cb574d3f22f63ebd493bfe20f94b6ab,val
046248,02747177,02747177,942887c8d668501681faebbdea6bd9be,val
046853,02747177,02747177,92fa62263ad30506d2b12aa6a0f050b3,val
046957,02747177,02747177,c77e8499be0ce1e04f3443b22038d340,val
048064,02747177,02747177,c18e807ff9858a51fb016d9401ff3e29,val
048971,02747177,02747177,18dbebd6527cffa254685f5f473de41f,val
051563,02747177,02747177,7c90fba6cd7f73871c1ef519b9196b63,val
I checked the type of split[5] and it is indeed string. I even tried
print(split[5] == 'val')
which prints false.
Thanks for the help!
There is a simpler (more generic) way of splitting your lines into buckets according to the last 'key', without using a series of if blocks to catch every possible 'key'. Something like this (use input redirection to load the file in this example):
local groups = {}
for line in io.lines() do
v,k = line:match '^(%d+),%d+,%d+,%x+,(%w+)$'
if v ~= nil and k ~= nil then -- or, just if k
local t = groups[k]
if t == nil then t = { v } else t[#t+1] = v end
groups[k] = t
end
end
-- And, to see table contents for verification...
for k,v in pairs(groups) do
print(k)
for i,v in ipairs(v) do print('',i,v) end
end
UPDATE/SOLUTION:
Thanks to the solution of Egor Skriptunoff in the comments, this has been solved. The problem is on Linux the CR and LF are interpreted differently, and I was indeed using a file made on Windows on Linux. So just ignoring the last character in every line solves it. According to Egor's solution modifying the inner for that is splitting with this works:
for token in line:gsub('\r', ''):gmatch('[^,]+') do
....
end
Thanks again to Egor for the solution and the explanation!
I am working on a Ruby challenge for work, and I am unable to create a working method. Every method I try keeps returning "nil".
Here is the question:
Create a method that passes an integer argument to a single parameter. If the integer is greater than 0 print the numbers from the integer to 0. If the number is less than 0 simply print the integer. Use a for loop, while loop, or unless loop to print the range of numbers from the integer to 0.
For example:
sample(4)
output = 3, 2, 1
sample(-1)
output = -1
Here is the code I tried to use
def countdown(n)
loop do
n -= 1
print "#{n}"
break if n <= 0
end
countdown(4)
A method returns the results of the last statement executed. Your loop is returning nil:
def countdown(n)
x = loop do
n -= 1
puts "#{n}"
break if n <= 0
end
x
end
countdown(4)
3
2
1
0
=> nil
Now let's return something:
def countdown(n)
loop do
puts "#{n}"
break if n <= 0
n -= 1
end
"okay we're done"
end
countdown(4)
4
3
2
1
0
=> "okay we're done"
It's not necessary to print inside the function and also outside it - this will cause duplicate printing. Also you are calling print on the positive numbers but not calling print if they are negative or zero. Additionally, you are using print "#{n}" which is the same as print n.
As far as the title of your question goes - "keeps returning nil" - you can change your approach a bit to do the print calls outside the function.
def countdown(n)
n <= 1 ? [n] : (n-1).downto(1).to_a
end
print countdown(n).join(", ")
Try this:
def countdown(n)
n.downto(n > 0 ? 0 : n) { |i| puts i }
end
countdown(4)
# 4
# 3
# 2
# 1
# 0
countdown(-4)
# -4
countdown(0)
# 0
You didn't mention what is to be done if the argument is zero. I've assumed it's treated as a positive or negative number.
Admittedly, this is cheating, as it does not "Use a for loop, while loop, or unless loop...", but Ruby is designed mainly to use iterators and blocks. This, or something like it, is the way to go. I just had a thought: treat that as a suggestion, not a requirement.
By the way, among loops, Kernel#loop was not mentioned, which is strange, as it is quite useful. As for "for loops", who uses them? I never have, not even once.
If you must use a loop, you could do the following.
def countdown(n)
while n > 0
puts n
n-= 1
end
puts n
end
countdown(4)
# 4
# 3
# 2
# 1
# 0
countdown(-4)
# -4
countdown(0)
# 0
You may try this...
def sample (a)
if a > 0
(1..a).to_a.reverse
else
a
end
end
Hope this will work for you
I'm trying to get the total cost in one of my field called "upgrade_cost" and store that in a variable called $tuc
def totalUpgradeCost
$e = Experience.all
$tuc = 0
(e.emf_assets).each do |i|
i.upgrade_cost += $tuc
end
return $tuc
end
I'm getting some error undefined local variable or method `e', new to ruby. Anyone help?
I am assuming that emf_assets are associated (via has_many) with an experience. That said I think the following could work for you:
def total_upgrade_cost
total = 0 # use a more descriptive variable names
all_experiences = Experience.all
all_experiences.each do |experience| # iterate over each `experiment`
experience.emf_assets.each do |asset| # load `emf_assets` for each `experiment`
# add the `upgrade_cost` (which might be `nil`) to `total`
total += asset.upgrade_cost.to_i
end
end
total # no need for an explicit `return`
end
Please note that this might work for smaller numbers of experiences and emf_assets, but in a next step performance will benefit from some optimization. But I think that optimization is out of the scope of this question at the moment. You will need to avoid the N+1 query problem and it might makes sense to do the whole calculation in your database.
What is the e in e.emf_assets? If you mean $e, you aren't allowed to drop the $. In Ruby, a $ at the start of a variable name indicates a global variable. If you aren't using $e outside of this function anyway, it would be better to call it simply e, so that it wouldn't be visible outside of the function. Regardless, you're getting an error because $e refers to a global, and e refers to a separate (undefined) local variable.
This is not PHP. $ sign isn't required everywhere. You've used $ with one e and left another empty, that's why the error.
This code should work:
def totalUpgradeCost
e = Experience.all
tuc = 0
e.emf_assets.each do |i|
tuc += i.upgrade_cost
end
return tuc
end
This is doable in shorter way:
def totalUpgradeCost
e = Experience.all
e.emf_assets.inject(0) {|sum, i| sum += i.upgrade_cost}
end
Why does
a = [].tap do |x|
x << 1
end
puts "a: #{a}"
work as expected
a: [1]
but
b = [].tap do |x|
x = [1]
end
puts "b: #{b}"
doesn't
b: []
?
The reason why the second snippet does not change the array is the same why this snippet:
def foo(x)
x = [1]
end
a = []
foo(a)
does not change variable a. Variable x in your code is local to the scope of the block, and because of that you can assign anything to it, but the assignment won't be visible outside (Ruby is a pass-by-value language).
Of course, blocks have also closures on the local variables where they were declared, so this will work:
def foo(x)
yield(x)
end
b = []
foo(123) do |x|
b = [1]
end
p b # outputs [1]
The first method put 1 on the end of an empty array. In the same way you cant say that an empty array is equal to 1. Rather you would try and replicate it...
b = [].tap do |x|
x.unshift(1)
end
This is just an example yet have a look at the method call you can use on an Array by typing.
Array.methods.sort
All the best and Good luck
This is slightly unrelated -- but that [].tap idiom is horrible. You should not use it. Even many of the people who used it in rails code now admit it's horrible and no longer use it.
Do not use it.