How to insert a new hash into existing hash in ruby - ruby-on-rails

I have two hashes:
p = {"name"=>"TRICHI", "subdistrict"=>{"WANDIWASH"=>"1234"}}
q = {"name"=>"VELLORE", "subdistrict"=>{"WANDIWASH"=>"4183"}}
I need to make this as
r = [{"name"=>"VELLORE", "subdistrict"=>{"WANDIWASH"=>"4183"}},
{"name"=>"TRICHI", "subdistrict"=>{"WANDIWASH"=>"1234"}}]

I guess you want this:
r = [] << p << q
# or r = [p, q]
# either way you'll get:
# [ {"name"=>"VELLORE", "subdistrict"=>{"WANDIWASH"=>"4183"}},
# {"name"=>"TRICHI", "subdistrict"=>{"WANDIWASH"=>"1234"}} ]
This way you will have an array with 2 hashes.

As Tim pointed, r doesn't seem to be a Hash, maybe you meant an Array, in which case you can do
r = [p,q]
or
r = []
r << p
r << q
.. keep going for any other entry you want to push into r

Related

Ruby << syntax method raises an error, but .push method not when using yield. Why?

I am trying to figure out why the case C is not working. As you can see when I use 'yield' and '<<' sugar syntax it raises an error, but if I use the method's name 'acc.push' it works. In the other hand, if I use the 'result' variable to get yield result and then add to acc array using << syntax, it works. I just would like to understand why it does not work in the case C. Thanks.
Case A - Working fine
def my_map(my_arr)
c = 0 # the counter
acc = [] # new array
until c == my_arr.length
acc.push(yield my_arr[c])
c += 1
end
acc
end
p my_map( [1,2,3,4] ) { |each| each * 10 }
Case B - Working fine
def my_map(my_arr)
c = 0 # the counter
acc = [] # new array
until c == my_arr.length
result = yield my_arr[c]
acc << result
c += 1
end
acc
end
p my_map( [1,2,3,4] ) { |each| each * 10 }
Case C - Error: syntax error, unexpected local variable or method, expecting `end' acc << yield my_arr[c]
def my_map(my_arr)
c = 0 # the counter
acc = [] # new array
until c == my_arr.length
acc << yield my_arr[c]
c += 1
end
acc
end
p my_map( [1,2,3,4] ) { |each| each * 10 }
While you expect that Ruby interprets acc << yield my_arr[c] as
acc.<<(yield(my_arr[c]))
Ruby actually understands it like this
acc.<<(yield)(my_arr[c])
Which doesn't make much sense. It can be fixed by using parentheses as others already mentioned:
acc << yield(my_arr[c])
You're hitting a case of operator precedence, which Ruby can't resolve for itself.
You can fix it by using parentheses to provide enough clarity for Ruby to work out how to parse the offending line:
acc << yield(my_arr[c])
Just use parenthesis for the yield method call.
acc << yield(my_arr[c])
My guess is that the << tries to add the yield directly to the array which results in the syntax error.

For a new index from two indexes in a for loop

I was working on lua and looped over two tables and wanted to create a new table out of it, with no nil values in it. So this is basically a cross product. E.g:
{1,2,3} x {3,4,5} -> {1*3,1*4,1*5,2*3,2*4,2*5,3*3,3*4,3*5}
Of course this is not hard to do:
t = {1,2,3}
s = {3,4,5}
xs = {}
q = 1
for i,h in ipairs(t) do
for j,k in ipairs(s) do
xs[q] = h * k
q = q + 1
end
end
We keep a counter q and add 1 every iteration. And this works fine. However is it also possible without a counter? Can I fill up x so with just i and j such that there are no gaps in x?
t = {1,2,3}
s = {3,4,5}
xs = {}
for i,h in ipairs(t) do
for j,k in ipairs(s) do
q = f(i,j) -- <- I want to know if f is possible to write
xs[q] = h * k
end
end
I would say not, at least I was not able to find one myself easily.
EDIT: It is possible though if I am allowed to use the size of s.
s = {1,2,3}
t = {4,5,6}
xs = {}
for i,h in ipairs(s) do
for j,k in ipairs(t) do
q = i + (j - 1) * #t
xs[q] = h * k
end
end
You can use table.insert, there is no reason to specify the index in your case.
s = {1,2,3}
t = {4,5,6}
xs = {}
for i,h in ipairs(s) do
for j,k in ipairs(t) do
table.insert(xs, h * k)
end
end
for _, v in ipairs(xs) do
print(v)
end
Resource on insert:
https://www.lua.org/pil/19.2.html

Get values of items inside a table

local sometable = {a = "ag", b = "fa"}
for k, v in ipairs(sometable) do
print(k, v)
end
The code above is my effort, so how do i print a, b in that table?!
You are using the wrong iterator. ipairs is for sequences. For hash-like tables, use pairs instead:
for k, v in pairs(sometable) do
ipairs only traversers the array part of a table. What you can do is simply writing
print(sometable.a, sometable.b)
or you can cycle through both the dictionary and array parts of the table by using
for key, value in pairs(sometable)
You could also define your own iterator to only cycle through the dictionary part of the table. In my mind it would look like
function cycle(dict)
local contentarray = {}
for k, v in pairs(dict) do
contentarray[#contentarray + 1] = {k, v}
end
local n = 0
return function()
n = n + 1
if not contentarray[n] then
return
else
while type(contentarray[n][1]) ~= "string" do
n = n + 1
end
return contentarray[n][1], contentarray[n][2]
end
end
end
But that would be higly inefficient.

One loop for iterating through multiple Lua tables

Is it possible to iterate through multiple Lua tables with the same loop?
For looping through indexed tables I can do something like this:
local t1 = {"a", "b", "c"}
local t2 = {"d", "e", "f"}
local num = #t1+#t2
for i=1, num, do
local j
local val
if i <= #t1 then
j = i
val = t1[j]
else
j = i-#t1
val = t2[j]
end
-- Do stuff
end
but how about key-value tables?
E.g. something like this:
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for key, val in pairs(t1) or pairs(t2) do
print(key..": '"..val.."'")
end
should result in this:
a: 'a'
b: 'b'
c: 'c'
d: 'd'
e: 'e'
f: 'f'
function pairs(t, ...)
local i, a, k, v = 1, {...}
return
function()
repeat
k, v = next(t, k)
if k == nil then
i, t = i + 1, a[i]
end
until k ~= nil or not t
return k, v
end
end
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for key, val in pairs(t1, t2) do
print(key..": '"..val.."'")
end
Note: this implementation does not respect __pairs metamethod.
For the given example, I think it is much more concise and clear to just wrap the loop in an outer loop that iterates the tables.
I am assuming the primary reason OP was looking for a solution other than two loops was to avoid having to write the inner logic twice. This is a good solution to that problem and only adds two lines of code:
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for _, tbl in ipairs({ t1, t2 }) do
for key, val in pairs(tbl) do
print(key..": '"..val.."'")
end
end
While it's always nice to have an iterator like Egor's, a more efficient solution would simply be
local t1 = {a="a", b="b", c="c"}
local t2 = {d="d", e="e", f="f"}
for key, val in pairs(t1) do
print(key..": "..val)
end
for key, val in pairs(t2) do
print(key..": '"..val)
end
It's simple, concise, and easily understandable.

"undefined method 'zero' for Nil:Class" when #sum the Array without Nils

The issue happens when the variable, that the array was built from, was a nil initially.
y = (1..2).map do
v = nil
v = 1
v
end
p y # => [1, 1]
p y.class # => Array(Int32)
p y.sum # => 2
When v stops being nil on a condition, that is potentially computational and not solvable while compiling:
z = (1..2).map do
v = nil
v = 1 if true
v
end
p z # [1, 1]
p z.class # => Array(Nil | Int32)
The array gets more complex type, that isn't compatible with current sum implementation, so p z.sum causes compile time error:
undefined method 'zero' for Nil:Class (compile-time type is (Nil | Int32):Class)
def sum(initial = T.zero)
^~~~
How am I supposed to fight this properly?
Or maybe it waits for some better implementation of stdlib sum method or anything else?
UPD: inject gives the same:
p z.inject{ |i, j| i + j }
undefined method '+' for Nil (compile-time type is (Nil | Int32))
You can use Iterator#compact_map to select non-nil values. The compiler will be able to infer a Array(Int32) in that case.
http://play.crystal-lang.org/#/r/e85
z = (1..2).map do
v = nil
v = 1 if true
v
end
pp typeof(z) # => Array(Nil | Int32)
pp z # => z = [1, 1]
y = z.compact_map(&.itself)
pp typeof(y) # => Array(Int32)
pp y # => y = [1, 1]
Also, notice that typeof(Expr) and Expr.class might lead to different results. The first is the compile time type and the later is the runtime type.
An alternative solution to what Brian says is to use sum with a block:
http://play.crystal-lang.org/#/r/ein
z = (1..2).map do
v = nil
v = 1 if true
v
end
puts z.sum { |x| x || 0 } #=> 2

Resources