Merge multiple arrays - ruby

I have an array of arrays as given below.
[
["Horse", 8, 0, 0, 0],
["Horse", 0, 0, 12, 0],
["Horse", 0, 7, 0, 0],
["Dog", 1, 0, 0, 0],
["Dog", 0, 0, 3, 0],
["Dog", 0, 3, 0, 0],
["Test", 5, 0, 0, 0],
["Test", 0, 0, 2, 0],
["Test", 0, 0, 0, 2],
["Cat", 5, 0, 0, 0],
["Cat", 0, 0, 4, 0],
["Cat", 0, 2, 0, 0]
]
I want to merge the different arrays who start with the same first elements together and replacing the 0 by the value who are at the same position inside the other array, like the result below.
[
["Horse", 8, 7, 12, 0],
["Dog", 1, 3, 3, 0],
["Test", 5, 0, 2, 2],
["Cat", 5, 2, 4, 0]
]
So far I have this function:
array.each_with_index do |line, idx|
if array[idx+1].present? && line[0] == array[idx+1][0]
line.each_with_index do |l, i|
if l != 0 && array[idx+1][i] == 0
array[idx+1][i] = array[idx][i]
end
end
end
end
But it is not completely what I'm trying to do, but i'm close. Does anyone have some insights?

Not certain what the question is, but assuming that the array given is arr, you can get the result by:
arr
.group_by(&:first)
.map{|k, v| [k, *v.transpose.drop(1).map{|a| a.inject(:+)}]}
or as pointed out by Cary Swoveland:
arr
.group_by(&:first)
.map{|k, v| [k, *v.transpose.drop(1).map(&:sum)]}
Result:
[
["Horse", 8, 7, 12, 0],
["Dog", 1, 3, 3, 0],
["Test", 5, 0, 2, 2],
["Cat", 5, 2, 4, 0]
]

Assuming your initial array of arrays is stored in arr:
arr.each_with_object(Hash.new { |h, k| h[k] = [0] * 4 }) do |(name, *vals), acc|
(0...vals.size).each { |i| acc[name][i] += vals[i] }
end.map { |k, v| [k, *v] }
#⇒ [["Horse", 8, 7, 12, 0],
# ["Dog", 1, 3, 3, 0],
# ["Test", 5, 0, 2, 2],
# ["Cat", 5, 2, 4, 0]]
The key to the solution is to maintain a hash and convert it to the array in the very end. The hash is easier to lookup and operate in general.
The accumulator uses the default values to simplify adding new values to.

arr = [["Horse", 8, 0, 0, 0], ["Horse", 0, 0, 12, 0], ["Horse", 0, 7, 0, 0],
["Dog", 1, 0, 0, 0], ["Dog", 0, 0, 3, 0], ["Dog", 0, 3, 0, 0],
["Test", 5, 0, 0, 0], ["Test", 0, 0, 2, 0], ["Test", 0, 0, 0, 2],
["Cat", 5, 0, 0, 0], ["Cat", 0, 0, 4, 0], ["Cat", 0, 2, 0, 0]]
require 'matrix'
arr.each_with_object({}) do |(k,*arr),h|
h[k] = h.key?(k) ? (h[k] + Vector[*arr]) : Vector[*arr]
end.map { |a,v| [a, *v.to_a] }
#=> [["Horse", 8, 7, 12, 0],
# ["Dog", 1, 3, 3, 0],
# ["Test", 5, 0, 2, 2],
# ["Cat", 5, 2, 4, 0]]
Requiring 'matrix' loads the class Vector as well as Matrix. See Vector::[], Vector#+ and Vector#to_a.
This does not require the elements of arr be ordered in any way.

with this you won't have limit after the name of animal ["Dog", 1, 4, 5, 0, 6, 3, ...]
array.group_by { |obj| obj[0] }.map do |key, values|
rest = values.reduce([]) do |memo, value|
value[1..-1].each_with_index do |item, i|
memo[i] ||= 0
memo[i] = [item, memo[i]].max
end
memo
end
[key] + rest
end

Following is simple one,
hash = array.group_by(&:first)
hash.map { |k,v| v.map { |x| x[1..-1] }.transpose.map {|x| x.reduce(:+)}.unshift(k) }

Related

Why method "div" is faster thant "div2"?

Im trying to decipher why the div method is faster than the div2 method, and I cant find the reason.
def div2(num)
[*1..num].select do |n|
n if num % n == 0
end
end
p div2(58463982)
def div(num)
result = []
(1..num).each do |n|
break if result.include?(num / n)
result.concat([n, num / n]).uniq! if num % n == 0
end
result.sort!
end
p div(58463982)
I will let others explain why div is faster than div2. I want to show how to compute the factors of the given natural number in a way that is considerably faster.
Every integer can be expressed as the product of a collection of prime numbers, each taken to a power of one or more. We can use the method Prime::prime_division to obtain those prime numbers and powers. For example,
require 'prime'
arr = Prime.prime_division(58463982)
#=> [[2, 1], [3, 2], [53, 1], [61283, 1]]
This means that:
(2**1) * (3**2) * (53**1) * (61283**1)
#=> 58463982
One divisor of 58463982 equals, for example:
(2**1) * (3**2) * (53**0) * (61283**1)
#=> 2 * 9 * 1 * 61283
#=> 1103094
To confirm:
58463982 % 1103094
#=> 0
Another would be
(2**0) * (3**1) * (53**1) * (61283**0)
#=> 1 * 3 * 53 * 1
#=> 159
We find that all factors of a given number can be computed (combinatorially) as follows, using the methods Array#product and Enumerable#reduce (a.k.a. inject).
def all_factors(n)
primes, exponents = Prime.prime_division(n).transpose
first_exp_range, *rest_exp_range = exponents.map { |e| [*0..e] }
first_exp_range.product(*rest_exp_range).map do |exps|
primes.zip(exps).reduce(1) { |t,(p,e)| t*(p**e) }
end.sort
end
Depending on requirements, .sort at the end may not be required.
We may test:
require 'time'
t = Time.now
p all_factors(58463982)
p Time.now - t
#=> [1, 2, 3, 6, 9, 18, 53, 106, 159, 318, 477, 954, 61283, 122566,
# 183849, 367698, 551547, 1103094, 3247999, 6495998, 9743997,
# 19487994, 29231991, 58463982]
#
#=> 0.001405 (seconds)
By constrast, computing the factors of 58463982 with div2 and div required 4.467112 and 0.021103 seconds, respectively.
This is clearly much faster than those methods.
We may step through the example to view the calculations being performed.
n = 58463982
then
primes, exponents = Prime.prime_division(n).transpose
#=> [[2, 3, 53, 61283], [1, 2, 1, 1]]
so
primes
#=> [2, 3, 53, 61283]
exponents
#=> [1, 2, 1, 1]
Then,
first_exp_range, *rest_exp_range = exponents.map { |e| [*0..e] }
#=> [[0, 1], [0, 1, 2], [0, 1], [0, 1]]
so
first_exp_range
#=> [0, 1]
rest_exp_range
#=> [0, 1, 2], [0, 1], [0, 1]
Then
a = first_exp_range.product(*res_exp_range)
#=> [[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 0, 1, 1],
# [0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1],
# [0, 2, 0, 0], [0, 2, 0, 1], [0, 2, 1, 0], [0, 2, 1, 1],
# [1, 0, 0, 0], [1, 0, 0, 1], [1, 0, 1, 0], [1, 0, 1, 1],
# [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 1, 1, 1],
# [1, 2, 0, 0], [1, 2, 0, 1], [1, 2, 1, 0], [1, 2, 1, 1]]
Then,
b = a.map { |exps| primes.zip(exps).reduce(1) { |t,(p,e)| t*(p**e) } }
#=> [1, 61283, 53, 3247999, 3, 183849, 159, 9743997, 9, 551547,
# 477, 29231991, 2, 122566, 106, 6495998, 6, 367698, 318,
# 19487994, 18, 1103094, 954, 58463982]
To view the result sorted,
b.sort
#=> [1, 2, 3, 6, 9, 18, 53, 106, 159, 318, 477, 954, 61283, 122566,
# 183849, 367698, 551547, 1103094, 3247999, 6495998, 9743997,
# 19487994, 29231991, 58463982]
The div2 method create a list from 1 to num then iterates over all of the elements in it.
The div method can break early, and so does not have to iterate as many times.

How to calculate the number of ways to represent n cents

I'm working on the following algorithm and wanted to know if my implementation is correct:
Given an infinite number of quarters, dimes, nickels and pennies,
write code to calculate the number of ways of representing n cents
This is without memoizing:
def count_ways(n)
return 0 if n < 0
return 1 if n == 0
count_ways(n-25) + count_ways(n-5) + count_ways(n-10) + count_ways(n-1)
end
No, you will be double-counting solutions, because you could first pick a quarter and then a dime or the other way around, but those solutions are essentially the same.
The easiest way to prevent double-counting is to make sure you never pick a coin that is bigger than the ones you already picked.
In code:
def count_ways(n, max_coin)
return 0 if n < 0
return 1 if n == 0
result = count_ways(n-1, 1)
result = result + count_ways(n- 5, 5) if max_coin >= 5
result = result + count_ways(n-10, 10) if max_coin >= 10
result = result + count_ways(n-25, 25) if max_coin >= 25
result
end
And call it with 25 as initial max coin
We can see if your code is correct quite easily. let's try making change for a dime. There are four ways: 1 dime, 2 nickels, 1 nickel and 5 pennies, and 10 pennies, yet count_ways(10) #=> 9.
You can do it as follows, using recursion.
Code
def count_ways(cents, coins)
if coins.size == 1
return (cents % coins.first) == 0 ? [cents/coins.first] : nil
end
coin, *remaining_coins = coins
(0..cents/coin).each_with_object([]) { |n, arr|
count_ways(cents-n*coin, remaining_coins).each { |a| arr << [n, *a] } }
end
Examples
coins = [25, 10, 5, 1]
count_ways(32, coins)
#=> [[0, 0, 0, 32], [0, 0, 1, 27], [0, 0, 2, 22], [0, 0, 3, 17], [0, 0, 4, 12],
# [0, 0, 5, 7], [0, 0, 6, 2], [0, 1, 0, 22], [0, 1, 1, 17], [0, 1, 2, 12],
# [0, 1, 3, 7], [0, 1, 4, 2], [0, 2, 0, 12], [0, 2, 1, 7], [0, 2, 2, 2],
# [0, 3, 0, 2], [1, 0, 0, 7], [1, 0, 1, 2]]
count_ways(100, coins)
#=> [[0, 0, 0, 100], [0, 0, 1, 95], [0, 0, 2, 90], [0, 0, 3, 85], [0, 0, 4, 80],
# [0, 0, 5, 75], [0, 0, 6, 70], [0, 0, 7, 65], [0, 0, 8, 60], [0, 0, 9, 55],
# ...
# [3, 1, 2, 5], [3, 1, 3, 0], [3, 2, 0, 5], [3, 2, 1, 0], [4, 0, 0, 0]]
count_ways(100, coins).size
#=> 242
Explanation
The best way to show how the recursion works is to salt the code with puts statements and then run it against a simple example.
INDENT = 8
#indentation = 0
def indent
#indentation += INDENT
end
def undent
#indentation = [#indentation-INDENT, 0].max
end
def ind
' '*#indentation
end
def count_ways(cents, coins)
puts "#{ind}** entering count_ways with cents=#{cents}, coins=#{coins}"
if coins.size == 1
puts "#{ind}<< returning [cents]=#{[cents]} as coins.size == 1"
undent
end
return [cents] if coins.size == 1
coin, *remaining_coins = coins
puts "#{ind}coin=#{coin}. remaining_coins=#{remaining_coins}"
puts "#{ind}0..cents/coin=#{0..cents/coin}"
arr = (0..cents/coin).each_with_object([]) do |n, arr|
puts "#{ind} n=#{n}, arr=#{arr}"
puts "#{ind} >> calling count_ways(#{cents}-#{n}*#{coin}, remaining_coins)"
indent
aa = count_ways(cents-n*coin, remaining_coins)
puts "#{ind} aa=#{aa}"
aa.each do |a|
arr << [n, *a]
puts "#{ind} arr << [#{n}, *#{a}], arr=#{arr}"
end
puts "#{ind} after all coins, arr=#{arr}"
end
puts "#{ind}<< returning arr=#{arr}"
undent
arr
end
Now let's run count_ways(12, coins) which should return the four ways of making change for 12 cents: [[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]].
count_ways(12, coins)
** entering count_ways with cents=12, coins=[25, 10, 5, 1]
coin=25. remaining_coins=[10, 5, 1]
0..cents/coin=0..0
n=0, arr=[]
>> calling count_ways(12-0*25, remaining_coins)
** entering count_ways with cents=12, coins=[10, 5, 1]
coin=10. remaining_coins=[5, 1]
0..cents/coin=0..1
n=0, arr=[]
>> calling count_ways(12-0*10, remaining_coins)
** entering count_ways with cents=12, coins=[5, 1]
coin=5. remaining_coins=[1]
0..cents/coin=0..2
n=0, arr=[]
>> calling count_ways(12-0*5, remaining_coins)
** entering count_ways with cents=12, coins=[1]
<< returning [cents]=[12] as coins.size == 1
aa=[12]
arr << [0, *12], arr=[[0, 12]]
after all coins, arr=[[0, 12]]
n=1, arr=[[0, 12]]
>> calling count_ways(12-1*5, remaining_coins)
** entering count_ways with cents=7, coins=[1]
<< returning [cents]=[7] as coins.size == 1
aa=[7]
arr << [1, *7], arr=[[0, 12], [1, 7]]
after all coins, arr=[[0, 12], [1, 7]]
n=2, arr=[[0, 12], [1, 7]]
>> calling count_ways(12-2*5, remaining_coins)
** entering count_ways with cents=2, coins=[1]
<< returning [cents]=[2] as coins.size == 1
aa=[2]
arr << [2, *2], arr=[[0, 12], [1, 7], [2, 2]]
after all coins, arr=[[0, 12], [1, 7], [2, 2]]
<< returning arr=[[0, 12], [1, 7], [2, 2]]
aa=[[0, 12], [1, 7], [2, 2]]
arr << [0, *[0, 12]], arr=[[0, 0, 12]]
arr << [0, *[1, 7]], arr=[[0, 0, 12], [0, 1, 7]]
arr << [0, *[2, 2]], arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2]]
after all coins, arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2]]
n=1, arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2]]
>> calling count_ways(12-1*10, remaining_coins)
** entering count_ways with cents=2, coins=[5, 1]
coin=5. remaining_coins=[1]
0..cents/coin=0..0
n=0, arr=[]
>> calling count_ways(2-0*5, remaining_coins)
** entering count_ways with cents=2, coins=[1]
<< returning [cents]=[2] as coins.size == 1
aa=[2]
arr << [0, *2], arr=[[0, 2]]
after all coins, arr=[[0, 2]]
<< returning arr=[[0, 2]]
aa=[[0, 2]]
arr << [1, *[0, 2]], arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
after all coins, arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
<< returning arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
aa=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
arr << [0, *[0, 0, 12]], arr=[[0, 0, 0, 12]]
arr << [0, *[0, 1, 7]], arr=[[0, 0, 0, 12], [0, 0, 1, 7]]
arr << [0, *[0, 2, 2]], arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2]]
arr << [0, *[1, 0, 2]], arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
after all coins, arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
<< returning arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
=> [[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
The order of the coins doesn't matter, so coins.min isn't going to help you in this case – it's over-complicating things.
First we must develop an intuition about the relationship between the kinds of coins and the amount of change to count
The number of ways to change amount a using n kinds of coins equals
the number of ways to change amount a using all but the first kind of coin, plus
the number of ways to change amount a − d using all n kinds of coins, where d is the denomination of the first kind of coin.
source: SICP Chapter 1.2
### change_coins :: (Int, [Int]) -> Int
def change_coins amount, (x,*xs)
if amount == 0
1
elsif amount < 0 or x.nil?
0
else
change_coins(amount, xs) + change_coins(amount - x, [x,*xs])
end
end
change_coins 11, [1, 2, 5] # => 11
change_coins 2, [3] # => 0
change_coins 100, [1, 5, 10, 25, 50] # => 292
Sensible return values
For example, in this problem we have to return -1 if the amount of money cannot be made up by any combination of the coins.
The -1 case is dumb. There are zero ways to change 2 cents using only a 3-cent coin; therefore we return 0.
If you really must return -1, just use a stupid wrapper
def cc amount, xs
count = change_coins amount, xs
if count == 0 then -1 else count end
end
Order doesn't matter
change_coins 11, [5, 1, 2] # => 11
change_coins 2, [3] # => 0
change_coins 100, [50, 1, 25, 10, 5] # => 292

`each` loop with additional parameter

I expected row to be [0, 0, 0, 0] and row_index to be nil in the following:
img_array = [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
]
img_array.each do |row, row_index|
...
end
Actually, row is 0 and row_index is 0. Can anyone explain this?
img_array = [
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 0, 1]
]
We have:
enum = img_array.each
#=> #<Enumerator: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1]]:each>
Array#each therefore creates an enumerator that is an instance of the class Enumerator. The method Enumerator#each passes each element of enum to the block and assigns the block variables:
enum.each { |row, row_index| puts "row=#{row}, row_index=#{row_index}" }
# row=0, row_index=1
# row=4, row_index=5
# row=8, row_index=9
We can see what each of the elements of enum are by using the method Enumerator#next:
enum.next #=> StopIteration: iteration reached an end
Whoops! I forgot to reset the enumerator:
enum.rewind
#=> #<Enumerator: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1]]:each>
enum.next #=> [0, 1, 2, 3]
enum.next #=> [4, 5, 6, 7]
enum.next #=> [8, 9, 0, 1]
enum.next #=> StopIteration: iteration reached an end
Alternatively, we could convert the enumerator to an array (no need to rewind):
enum.to_a #=> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1]]
When the element ([0, 1, 2, 3]) is passed to the block, the block variables are assigned as follows:
row, row_index = [0, 1, 2, 3] #=> [0, 1, 2, 3]
row #=> 0
row_index #=> 1
If the variables were |row, row_index, col_index|, the assignment would be:
row, row_index, col_index = [0, 1, 2, 3] #=> [0, 1, 2, 3]
row #=> 0
row_index #=> 1
col_index #=> 2
If they were |row, row_index, *rest|, it would be:
row, row_index, *rest = [0, 1, 2, 3] #=> [0, 1, 2, 3]
row #=> 0
row_index #=> 1
rest #=> [2, 3]
This is called parallel (or multiple) assignment. You can read up on the rules for such assignments at the link I've given.
The method .each() on array in Ruby will call your block with only one argument.
So if you write your code like this:
img_array.each do |row, row_index|
# do something here
end
It will equivalent to this:
img_array.each do |element|
row, row_index = element
# and now
# row = element[0]
# row_index = element[1]
end
I made an example that easier to understand
img_array = [
['a', 'b', 'd', 'e'],
['f', 'g', 'h', 'j']
]
img_array.each do |row, row_index|
p row
p row_index
end
And the result will be:
"a"
"b"
"f"
"g"
Run it online here: https://ideone.com/ifDaVZ

Multidimensional array of zeros in 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]]

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