Iterate array using range - ruby

This is what I want to do
a = [1, 2, 3, 4]
a[1] = 0
a[2] = 0
one way to do this is to loop
(1..2).each { |x| x = 0 }
is there a way to do this somehow with ranges or splats? something like
a[(1..2)] = 0

a = [1, 2, 3, 4]
a[1..2] = [0] * 2
p a #[1, 0, 0, 4]
You can't just type a[1..2] = 0 at line 2, cause the array a will become [1, 0, 4]

Or, with Array#fill
a.fill(0, 1..2)

With range
ary = [1, 2, 3, 4]
ary[1..2] = [0,0]
Using [start, length]
a = [1,2,3,4]
a[1,2] = [0,0]

Related

How do I add together two arrays and get the result back as one number? Ruby

I need to add together two arrays of numbers and print the result as a total number.
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
arr1 + arr2
Just gives me = 1 2 3 4 5 6, but I want 21.
you can use the sum method
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
(arr1 + arr2).sum
This is another way
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
p (arr1 + arr2).reduce(:+)
Output
21

Algorithm for array with `while` or `until` loop

I have:
array = [1, 4, -1, 3, 2]
I want a new array that follows the following logic:
First element is located at index 0, so it is 1.
Second element is located at index 1 (because value for index 0 was 1).
Third element is located at index 4, so it is 2.
And so on until the loop meets value -1, which is the last value, and it should brake.
The new array should be:
[1, 4, 2, -1]
I have:
def task(a)
array = []
a.each_with_index do |v, i|
result = a[i]
until a[i] == -1
array << a[result]
end
end
puts result
end
As others say, you need to change the index in your loop. Also, if you want -1 in the result, you should exit at bottom. And with_index will give you indices in order, which is not what you want here. This will do what you want:
def task(a)
i = 0
array = []
begin
i = a[i]
array << i
end until i == -1
array
end
p task([1, 4, -1, 3, 2])
# => [1, 4, 2, -1]
until a[i] == -1
array << a[result]
end
This code is looping eternally - there is nothing to change i .
As discussed in the comments, you are looping through the array which is not what you require.
You could use a recursive method to handle jumping from one element to another based on previous value. Consider the following:
arr = [1, 4, -1, 3, 2]
def task(arr, n=0, result=[])
if arr[n] == -1
return result + [-1]
end
r = arr[n]
task(arr, r, result + [r])
end
puts task(arr)
input_array = [1, 4, -1, 3, 2]
last_valid_index = input_array.find_index { |entry| entry < 0 }
first_element = input_array.first
last_element = input_array[last_valid_index]
middle_elements = (1..last_valid_index).map { |i| input_array[input_array[i-1]]}
output_array = [first_element] + middle_elements + [last_element]
p output_array
# => [1, 4, 2, -1]
you could to most of it on one line like so, but I think the more verbose version is more self documenting.
input_array = [1, 4, -1, 3, 2]
last_valid_index = input_array.find_index { |entry| entry < 0 }
output_array = [input_array.first] + (1..last_valid_index).map { |i| input_array[input_array[i-1]]} + [input_array[last_valid_index]]
p output_array
# => [1, 4, 2, -1]
I'd suggest this option, just to avoid infinite loops or index out range:
i, ary = 0, [array[0]]
array.size.times do
break if array[i] == -1 or array[i] > array.size - 1
i = array[i]
ary << array[i]
end
ary #=> [1, 4, 2, -1]
An infinite loop happens for example when array = [1, 4, -1, 0, 3].
Index out of range can happen when array = [1, 4, 6, 3, 2]

Ruby: recursive method

def reverse_append(arr, n)
return arr if n < 0
reverse_append(arr, n-1)
arr << n
arr
end
reverse_append([],4) #=> [0, 1, 2, 3, 4]
I can't seem to understand this recursive method. It produces an array from 0 up to n.
Can someone explain this to me?
The method reverse_append([],4) is called
Since 4 >= 0, the return statement does not get called.
The method reverse_append([],3) is called.
Since 3 >= 0, the return statement does not get called.
The method reverse_append([],2) is called.
Since 2 >= 0, the return statement does not get called.
The method reverse_append([],1) is called.
Since 1 >= 0, the return statement does not get called.
The method reverse_append([],0) is called.
Since 0 >= 0, the return statement does not get called.
The method reverse_append([],-1) is called.
Since -1 < 0, the array ([]) is returned.
We pop up one level in our call stack, to where n = 0 and arr = [].
arr << n and arr is returned, so now arr = [0].
We pop up one level in our call stack, to where n = 1 and arr = [0].
arr << n and arr is returned, so now arr = [0, 1].
We pop up one level in our call stack, to where n = 2 and arr = [0, 1].
arr << n and arr is returned, so now arr = [0, 1, 2].
We pop up one level in our call stack, to where n = 3 and arr = [0, 1, 2].
arr << n and arr is returned, so now arr = [0, 1, 2, 3].
We pop up one level in our call stack, to where n = 4 and arr = [0, 1, 2, 3].
arr << n and arr is returned, so now arr = [0, 1, 2, 3, 4].
Finally, the "top-level" method returns, and we have our final result.
Well step through the code with the supplied parameters. The first step is to check if n < 0 which its not. If it isn't 0 reverse append with [], 3 and appends the that array the number and then returns the array.
So it takes the array, adds 4 to it after it has gone through the step of dealing with [], 3, [], 2, [],1 and [], 0. So the first call that will succeed is just returning the array when it gets below 0, next is 0 gets appended, then one, then 2, then 3 and lastly the original call with 4 gets added arr << n.
There's a nice tool you can add to many editors called "Seeing Is Believing", which lets you see what is happening as code runs:
def reverse_append(arr, n)
return arr if n < 0 # => false, false, false, false, true
reverse_append(arr, n-1) # => [], [0], [0, 1], [0, 1, 2]
arr << n # => [0], [0, 1], [0, 1, 2], [0, 1, 2, 3]
arr # => [0], [0, 1], [0, 1, 2], [0, 1, 2, 3]
end
reverse_append([], 3) # => [0, 1, 2, 3]
However, with a name like "reverse_append" it seems like you should see a result that is descending in values:
def reverse_append(arr, n)
return arr if n < 0 # => false, false, false, false, true
reverse_append(arr, n-1) # => [], [0], [1, 0], [2, 1, 0]
arr.unshift n # => [0], [1, 0], [2, 1, 0], [3, 2, 1, 0]
arr # => [0], [1, 0], [2, 1, 0], [3, 2, 1, 0]
end
reverse_append([], 3) # => [3, 2, 1, 0]
In either case, there are a lot of easier ways to generate such an array without relying on recursion:
[*0..3] # => [0, 1, 2, 3]
(0..3).to_a # => [0, 1, 2, 3]
[*0..3].reverse # => [3, 2, 1, 0]
(0..3).to_a.reverse # => [3, 2, 1, 0]

Ruby: Permutation on an Array

Say, I have an array:
a = [1,2]
and
n = 3
I want output like this:
[[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1, 2], [2, 2, 1], [2, 2, 2]]
This are all possible combinations of length n of elements from array a.
Most importantly I'm using ruby 1.8.7
a.repeated_combination(n).to_a
Please test in detail before use:
x = [1,0]
n = 3
def perm(a, n)
l = a.length
(l**n).times do |i|
entry = []
o = i
n.times do
v = o % l
entry << a[v]
o /= l
end
yield(i, entry)
end
end
perm(x, n) do |i, entry|
puts "#{i} #{entry.reverse.inspect}"
end
prints
0 [0, 0, 0]
1 [0, 0, 1]
2 [0, 1, 0]
3 [0, 1, 1]
4 [1, 0, 0]
5 [1, 0, 1]
6 [1, 1, 0]
7 [1, 1, 1]

Build efficient array integer incrementer with different caps per number

I want to program a counter which is represented by an array of numbers, starting with:
[0, 0, 0]
The constraint here is, that each position has a different cap, so it's not necessarily 9 or something else, but it is given. For instance:
[4, 2, 1]
Which would lead to the following incrementation sequence:
[0, 0, 0]
[0, 0, 1]
[0, 1, 0]
[0, 1, 1]
[0, 2, 0]
[0, 2, 1]
[1, 0, 0]
.
.
.
Of course I can think of a solution using modulo and adding each carryover onto the next position. But has someone an idea how to implement this efficiently, respectively with nice Ruby syntax without cluttering it too much?
That is my naive implementation:
max = [10, 1, 1, 1, 10]
counter = [0, 0, 0, 0, 0]
i = counter.length-1
while counter != max do
counter[i] = counter[i] + 1
while counter[i] > max[i]
counter[i] = 0
i = i - 1
counter[i] = counter[i] + 1
end
i = counter.length-1
end
I'm not sure about efficiency but here's my shot at it:
start = [0, 0, 0]
cap = [4, 2, 1]
start.zip(cap).map{ |i, c| (i..c).to_a }.reduce(&:product).map &:flatten
Produces something like:
[[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[0, 2, 0],
[0, 2, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1],
[1, 2, 0],
[1, 2, 1],
[2, 0, 0],
[2, 0, 1]...]
Edit: I was writing this before you made your edit. It seemed like you wanted a counter object, not just to output a list.
1) I would recommend specifying not the limits but (limit+1) of each of the digits. For example, for a [second, minute, hour, day, year] counter it makes more sense (to me) to write [60, 60, 24, 365] instead of [59,59,23,364].
2) You'll have to figure out what to do if your counter overflows the last limit of your array. I added an extra position that counts to infinity.
3) I would also recommend reversing the order of the array, at least in the internal representation to avoid inverting subscripts. If you don't want it like that, you can .reverse the bases in initialize and #digits in to_s
class MyCounter
def initialize bases
#bases = bases
#bases << 1.0/0 # Infinity
#digits = Array.new(bases.size, 0)
prod = 1
#digit_values = [1] + #bases[0..-2].map { |b| prod *= b }
end
attr_reader :digit_values
def to_s
#digits
end
def increment(digit=0)
v = #digits[digit] + 1
if v < #bases[digit]
#digits[digit] = v
else
#digits[digit] = 0
increment(digit+1)
end
self
end
def +(integer)
(#digits.size - 1).step(0,-1).each do |i|
#digits[i] += integer / #digit_values[i]
integer = integer % #digit_values[i]
end
self
end
end
c1 = MyCounter.new [2,3,5]
20.times { c1.increment; p c1 }
c2 = MyCounter.new [2,3,5]
c2 += 20
p c2
Create an array for each cap, with values from 0 upto cap. Take the first array and calculate the Cartesian product with the rest of the arrays.
caps = [4, 2, 1]
arrs = caps.map{|cap| (0..cap).to_a} #=>[[0, 1, 2, 3, 4], [0, 1, 2], [0, 1]]
p arrs.shift.product(*arrs)
# =>[[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [0, 2, 0], [0, 2, 1], ...
If you don't want a memory-consuming array with the results, then provide a block. product will yield each element to it, one by one.
arrs = caps.map{|cap| (0..cap).to_a}
arrs.shift.product(*arrs){|el| puts el.join} #no resulting array
#000
#001
#010
#011
#...

Resources