Multidimensional array of zeros in Ruby - ruby

To create a one-dimensional array, I can write:
arr = Array.new(10) { |z| 0 }
#=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
But I want to know how to initialize an array in more dimensions, e.g.:
#=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
This is just an example. I am trying to understand the general case.

You can easily nest multiple Array.new calls:
Array.new(2, 0)
#=> [0, 0]
Array.new(3) { Array.new(2, 0) }
#=> [[0, 0], [0, 0], [0, 0]]
Array.new(4) { Array.new(3) { Array.new(2, 0) } }
#=> [[[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]]]
Note that the non-block version, i.e. Array.new(2, 0), should only be used for immutable objects, because the same object will be used for all elements. See the Common gotchas section for details.
To build an array of arbitrary dimensions, you could use recursion:
def multi_array(sizes, default = nil)
size, *remaining = sizes
if remaining.empty?
Array.new(size, default)
else
Array.new(size) { multi_array(remaining, default) }
end
end
multi_array([4, 3, 2], 0)
#=> [[[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]]]

You can also do it like:
Array.new(10, 0).each_slice(2).to_a
# => [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
5.times.map{Array.new(2, 0)}
# => [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]

If by more dimensions you mean an array of array, you could try:
arr = Array.new(10){|z| z=Array.new(2,0)}
# => [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0,0]]
assuming that your second dimension is 2.

I am trying to understand the general case.
Array.new(n) # where n is natural number 1..n
#=>[nil, nil, nil]
This will create a 1-D Array i:e One dimension array.
Let extends further for a multi-dimensional array i:e Two dimension array .
In ruby, every method accepts a block.
Array.new(3) do
Array.new(3)
end
end
Same can be written In online (macro style) Array.new(3) { Array.new(3) }
[
[nil, nil, nil],
[nil, nil, nil],
[nil, nil, nil]
]
Further, it can extend to initialize each cell value.
Array.new(3) do
Array.new(3) do
0
end
end
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
One line micro style Array.new(3) { Array.new(3) { 0 } }
Let extends further three-dimension array.
Array.new(2) do
Array.new(3) do
Array.new(4) do
0
end
end
end
OR
The same can be written as micro-style syntax
Array.new(2) { Array.new(3) { Array.new(4) } {0} }
[
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
]

Here's another way, though I feel the deep copy at every level could somehow be simplified:
def make_multi(dimensions, default)
dimensions.reverse.each_with_index.reduce([]) { |a,(d,i)|
Array.new(d) { i.zero? ? default : Marshal.load(Marshal.dump(a)) } }
end
arr = make_multi [4,3,2,2], 0
#=> [[[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]]]
arr[0][0][0][0] = 1
arr
#=> [[[[1, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]]]
arr = make_multi [4,3,2,2], {}
#=> [[[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]],
# [[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]],
# [[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]],
# [[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]]]
arr[0][0][0][0] = { a: 1 }
arr
#=> [[[[{:a=>1}, {}...] # all but the first are empty hashes

Try it:)
arr = Array.new(10, 0)
UPD: for multidimensional is:
arr = Array.new(10, Array.new(2, 0))
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]

Related

Getting all paths in an array

I have a list structured like follows:
s = [
[
[[0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0]],
[[0, 0, 0], [0, 1, 1]],
[[1, 0, 0], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]],
[[1, 0, 0], [0, 0, 0]],
],
[
[[1, 0, 0], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]],
[[0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0]],
[[0, 1, 0], [0, 0, 1]],
[[0, 0, 0], [0, 1, 1]]
],
# And so on
]
For each element at the first index, s[0], if the second sub-array, s[0][i][1], matches a corresponding first element in s[1], then we have a path, or a part of a path. It's complicated so I'll give an example:
s = [
[
[[0, 1, 1], *[0, 0, 0]*], <---- This goes to multiple possibilities
[[0, 0, 1], [0, 1, 0]],
[[0, 0, 0], [0, 1, 1]],
[[1, 0, 0], [0, 0, 0]],
[[0, 0, 0], [1, 0, 0]],
[[1, 0, 0], [0, 0, 0]],
],
[
[[1, 0, 0], [0, 0, 0]],
[*[0, 0, 0]*, [1, 0, 0]], <- here
[[0, 1, 1], [0, 0, 0]],
[[0, 0, 1], [0, 1, 0]],
[[0, 1, 0], [0, 0, 1]],
[*[0, 0, 0]*, [0, 1, 1]] <- and here
],
# And so on
]
How can I find the amount of paths for each given element?

displace an element in array by sum

I am trying to displace an array by adding a value to every element and then adding those new values to the array (array are x,y,z > sketchup) example:
arr = [[2.99213, 0, 0],
[2.93025, 0.0031909, 0],
[2.86903, 0.0127298, 0],
[2.80912, 0.0285154, 0]]
Adding 2 to every first element to get this:
arr = [[4.99213, 0, 0],
[4.93025, 0.0031909, 0],
[4.86903, 0.0127298, 0],
[4.80912, 0.0285154, 0]]
finally, adding the two arrays:
arr = [[2.99213, 0, 0],
[2.93025, 0.0031909, 0],
[2.86903, 0.0127298, 0],
[2.80912, 0.0285154, 0],
[4.99213, 0, 0],
[4.93025, 0.0031909, 0],
[4.86903, 0.0127298, 0],
[4.80912, 0.0285154, 0]]
Like this?
arr = [[2.99213, 0, 0], [2.93025, 0.0031909, 0], [2.86903, 0.0127298, 0], [2.80912, 0.0285154, 0]]
arr + arr.map { |k| [k[0]+2] + k[1..-1] }
# => [[2.99213, 0, 0], [2.93025, 0.0031909, 0], [2.86903, 0.0127298, 0], [2.80912, 0.0285154, 0], [4.9921299999999995, 0, 0], [4.93025, 0.0031909, 0], [4.86903, 0.0127298, 0], [4.80912, 0.0285154, 0]]

Getting all tuples in Ruby

Say I have the following input:
inp = [2, 9, 3]
I need output as all tuples in mixed counting, like this:
outp = [[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], ..., [1, 8, 2]]
I know algorithm from Knuth vol 4a as direct loop solution, but I've heard ruby has some magic inside.
I am mostly C++ developer. My direct solution now looks like:
inparr = [2, 9, 3]
bmix = Array.new(inparr.size) { |i| 0 }
outp = Array.new
loop do
# some debug output
puts bmix.to_s
#visit next tuple
outp << bmix.clone
digit = inparr.size
while digit > 0 do
digit -= 1
if bmix[digit] + 1 < inparr[digit]
bmix[digit] += 1
break
end
bmix[digit] = 0
end
break if (bmix.select{|x| x != 0}.empty?)
end
How to rewrite it in several simple lines?
inp.
map { |i| (0...i).to_a }.
reduce(&:product).
map(&:flatten)
Used operations: Range, Enumerable#map, Enumerable#reduce, Array#product, Array#flatten.
You could use recursion.
def recurse(inp)
first, *rest = inp
rest.empty? ? [*0..first-1] : (0..first-1).flat_map do |e|
recurse(rest).map { |arr| [e, *arr] }
end
end
recurse [2, 4, 3]
#=> [[0, 0, 0], [0, 0, 1], [0, 0, 2],
# [0, 1, 0], [0, 1, 1], [0, 1, 2],
# [0, 2, 0], [0, 2, 1], [0, 2, 2],
# [0, 3, 0], [0, 3, 1], [0, 3, 2],
# [1, 0, 0], [1, 0, 1], [1, 0, 2],
# [1, 1, 0], [1, 1, 1], [1, 1, 2],
# [1, 2, 0], [1, 2, 1], [1, 2, 2],
# [1, 3, 0], [1, 3, 1], [1, 3, 2]]
If first, *rest = [2,4,3], then first #=> 2 and rest #=> [4,3].
See Enumerable#flat_map and Array#map. a ? b : c is called a ternery expression.
If e #=> 1 and arr #=> [2,1] then [e, *arr] #=> [1,2,1].
I will go to great lengths to avoid the use of Array#flatten. It's irrational, but to me it's an ugly method. That's usually possible using flat_map and/or the splat operator *.
Here's a mix of the 2 existing answers. It might be a bit more concise and readable:
head, *rest = inp.map{ |n| n.times.to_a }
head.product(*rest)
As an example:
inp = [2, 4, 3]
# => [2, 4, 3]
head, *rest = inp.map{ |n| n.times.to_a }
# => [[0, 1], [0, 1, 2, 3], [0, 1, 2]]
head.product(*rest)
# => [[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], [0, 1, 2], [0, 2, 0], [0, 2, 1], [0, 2, 2], [0, 3, 0], [0, 3, 1], [0, 3, 2], [1, 0, 0], [1, 0, 1], [1, 0, 2], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 2, 0], [1, 2, 1], [1, 2, 2], [1, 3, 0], [1, 3, 1], [1, 3, 2]]

Ruby array in hash assignment odd behavior

i'm attempting to understand why the following code behaves (to my knowledge) oddly.
[1] pry(main)> a = {}
=> {}
[2] pry(main)> a[1] = [[0,0]] * 7
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[3] pry(main)> a[2] = [[0,0]] * 7
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[4] pry(main)> a[1][2][0] = 3 # Should be one value changed, right?
=> 3
[5] pry(main)> a
=> {1=>[[3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0]],
2=>[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]}
What i thought should happen is that one value of the array in the hash a at key 1 at index 2 should change to 3, but instead all the first values of the entire array change to 3. What's going on here, what am I missing? Here's my Ruby version.
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
EDIT:
I also tried the following
[1] pry(main)> a = {}
=> {}
[2] pry(main)> a[1] = ([[0,0].dup].dup * 7).dup
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[3] pry(main)> a[2] = ([[0,0].dup].dup * 7).dup
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[4] pry(main)> a[1][2][0] = 3
=> 3
[5] pry(main)> a
=> {1=>[[3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0]],
2=>[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]}
[6] pry(main)> a = {}
=> {}
[7] pry(main)> a[1] = ([[0,0].clone].clone * 7).clone
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[8] pry(main)> a[2] = ([[0,0].clone].clone * 7).clone
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
[9] pry(main)> a
=> {1=>[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]],
2=>[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]}
[10] pry(main)> a[1][2][0] = 3
=> 3
[11] pry(main)> a
=> {1=>[[3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0], [3, 0]],
2=>[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]}
Surely the values should be copies?
All the elements in a[1] refer to the same array.
[0,0] isn't deep-copied when you do [[0,0]] * 7.
Solution: a[1] = Array.new(7) { [0,0] } (thanks #Stefan!)
Here's how to diagnose this problem in the future:
object_id will tell you the "slot" where Ruby keeps an object. Objects should have unique IDs:
foo = []
bar = []
foo.object_id # => 70322472940660
bar.object_id # => 70322472940640
If they don't, though they might be different variable names, they're still pointing to the same object. That might be desirable in more advanced uses, but generally it's not something you want because changing one will change the other leading to confusion, gnashing teeth and possibly the return of "he who should not be named". For instance, we get fooled when we look at:
[[]] * 2 # => [[], []]
because it seems that we're getting back two arrays, which could be assigned using parallel assignment, like:
foo, bar = [[]] * 2
But, when we look at foo and bar to see where they're stored we can see the problem, they're both pointing to the same slot, and so changing one changes the other:
foo.object_id # => 70323794190700
bar.object_id # => 70323794190700
foo << 1
bar # => [1]
This is an ages old problem when writing code; You gotta learn about "pass by value" vs. "pass by reference" and when a language is doing one or the other otherwise this problem will occur. And then you have to learn how to tell the language to avoid the problem.

Binary Sequence Combination Generator, in Ruby

Code works, but feels very brute force, suggestions?
Goal of the code is to supply an array length, and then as fast as possible generate all possible unique binary combinations with that array length.
CODE:
class Array
def sequence(i = 0, *a)
return [a] if i == size
self[i].map {|x|
sequence(i+1, *(a + [x]))
}.inject([]) {|m, x| m + x}
end
end
[(0..1),(0..1),(0..1)].sequence
OUTPUTS:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
permutation and repeated_permutation are built in, so you can do:
def sequence(n)
[0, 1].repeated_permutation(n).to_a
end
p sequence(3) #=>[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
"All unique binary combinations" with n bits is nothing but (0...2**n), so the only task is to efficiently convert from an integer to its binary representation, and the following is a solution that does not rely on string generation/manipulation:
def sequence(n)
ret = []
(2**n).times do |number|
ret << []
(n - 1).downto(0) do |bit|
ret.last << number[bit]
end
end
ret
end
sequence(3)
# => [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
Or, if you prefer a version more oriented on list operations, this is pretty much the same:
def sequence(n)
(0...2**n).map {|number|
(1..n).map {|bit|
number[n-bit]
}
}
end

Resources