`each` loop with additional parameter - ruby

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

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.

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]]

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

ruby uniq with replacement

Normal uniq:
[1, 2, 3, 1, 1, 4].uniq => [1, 2, 3, 4]
I want to replace the duplicate with a replacement at where it was.
Is there a method or way to achieve something like this?
[1, 2, 3, 1, 1, 4].uniq_with_replacement(-1) => [1, 2, 3, -1, -1, 4]
Thanks in advance!
Here's a one-liner:
a.fill{ |i| a.index(a[i]) == i ? a[i] : -1 }
Something like this?:
class Array
def uniq_with_replacement(v)
map.with_object([]){|value, obj| obj << (obj.include?(value) ? v : value) }
end
end
Now:
[1, 2, 3, 1, 1, 4].uniq_with_replacement(-1)
# => [1, 2, 3, -1, -1, 4]
[1, 2, 3, 1, 1, 2, 4].uniq_with_replacement(-1)
# => [1, 2, 3, -1, -1, -1, 4]
1 more:
arr = [1, 2, 3, 1, 1, 4]
value = -1
a = arr.each_with_index.to_a
#=> [[1, 0], [2, 1], [3, 2], [1, 3], [1, 4], [4, 5]]
b = (a - a.uniq(&:first)).map(&:last)
#=> [3, 4]
arr.map.with_index { |e,i| b.include?(i) ? value : e }
#=> [1, 2, 3, -1, -1, 4]

Swapping two numbers with while loop in Ruby

I'd like to get [[2, 1, 3], [1, 3, 2]] from [1, 2, 3] in Ruby.
For [1, 2, 3, 4], I'd like to get [[2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3]]
Rule: Within two numbers, if left one is smaller then it swap the position.
I have the following codes so far but it returns [[2, 3, 1], [2, 3, 1]]
What am I doing wrong here? I appreciate any inputs.
In amidakuji.rb
class Amidakuji
def initialize(column, rung)
#column = column
#rung = rung
#myarr = []
#per_arr = []
#build_arr = []
end
def build_initial
#arr = (1..#column).to_a
end
def swap_element
i = 0
arr = build_initial
while i < #column - 1 do
#build_arr << swap(arr, i)
i += 1
end
#build_arr
end
def swap(arr, a)
if arr[a] < arr[a + 1]
arr[a], arr[a + 1] = arr[a + 1], arr[a]
end
arr
end
end
In amidakuji_spec.rb
it 'should create an array with swapped elements' do
expect(#kuji1.swap_element).to eq ([[2, 1, 3], [1, 3, 2]])
end
Results
Failures:
expected: [[2, 1, 3], [1, 3, 2]]
got: [[2, 3, 1], [2, 3, 1]]
You can do this quite compactly by using the methods Enumerable#each_cons and Enumerable#map.
Code
def doit(arr)
(0...arr.size).each_cons(2).map do |i,j|
a = arr.dup
a[i], a[j] = a[j], a[i]
a
end
end
Examples
doit([1,2,3]) #=> [[2, 1, 3], [1, 3, 2]]
doit([1,2,3,4]) #=> [[2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3]]
doit([1,2,3,4,5]) #=> [[2, 1, 3, 4, 5], [1, 3, 2, 4, 5],
#=> [1, 2, 4, 3, 5], [1, 2, 3, 5, 4]]
Explanation
arr = [1,2,3,4]
b = (0...arr.size).each_cons(2)
#=> #<Enumerator: 0...4:each_cons(2)>
To view the contents of this enumerator:
b.to_a
#=> [[0, 1], [1, 2], [2, 3]]
Lastly
b.map do |i,j|
a = arr.dup
a[i], a[j] = a[j], a[i]
a
end
#=> [[2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3]]
In the last step, consider the first element of b that is passed to map, which assigns the following values to the block variables:
i => 0
j => 1
We then make a copy of arr, swap the elements offsets 0 and 1, making
a => [2, 1, 3, 4]
and then enter a at the end of the block, causing map to replace [0, 1] with that array.
Given what you're trying to accomplish and the output you're getting, it looks like you're reusing the same array when you want distinct arrays instead. Specifically this line:
#build_arr << swap(arr, i)
is always passing the same 'arr' to swap.
So first time, it swaps the 1 and the 2 to give you [2, 1, 3]
Second time, it swaps the 1 and the 3 give you [2, 3, 1]
You push the same array onto #build_arr twice, which is why it repeats.

Resources