cycle through array using index - ruby

I have an array
arr = [1,2,3,4,5]
and I'm wondering if there is a way to cycle through it so something like:
i = 2
arr[3+n]
would return 1, rather than nil
Is that possible using the index, or even with next?

It's called cycle:
c = [1,2,3,4,5].cycle
10.times{p c.next}

Perform a modulo on the index using the array size:
arr = [1, 2, 3, 4, 5]
arr[5 % arr.size] #=> 1

Related

How to refactor this code to remove output variable?

def peel array
output = []
while ! array.empty? do
output << array.shift
mutate! array
end
output.flatten
end
I have not included the mutate! method, because I am only interested in removing the output variable. The mutate! call is important because we cannot iterate over the array using each because array is changing.
EDIT: I am getting an array as output, which is what I want. The method works correctly, but I think there is a way to collect the array.shift values without using a temp variable.
EDIT #2: OK, here is the mutate! method and test case:
def mutate! array
array.reverse!
end
a = (1..5).to_a
peel( a ).should == [ 1, 5, 2, 4, 3 ]
It doesn't matter if peel modifies array. I guess it should be called peel!. Yes, mutate! must be called after each element is removed.
All this reversing makes me dizzy.
def peel(array)
indices = array.size.times.map do |i|
i = -i if i.odd?
i = i/2
end
array.values_at(*indices) # indices will be [0, -1, 1, -2, 2] in the example
end
a = (1..5).to_a
p peel(a) #=>[1, 5, 2, 4, 3]
Another approach:
def peel(array)
mid = array.size/2
array[0..mid]
.zip(array[mid..-1].reverse)
.flatten(1)
.take(array.size)
end
Usage:
peel [1,2,3,4,5,6]
#=> [1, 6, 2, 5, 3, 4]
peel [1,2,3,4,5]
#=> [1, 5, 2, 4, 3]
Here's a way using parallel assignment:
def peel array
n = array.size
n.times {|i| (n-2-2*i).times {|j| array[n-1-j], array[n-2-j] = array[n-2-j], array[n-1-j]}}
array
end
peel [1,2,3,4,5] # => [1,5,2,4,3]
peel [1,2,3,4,5,6] # => [1,6,2,5,3,4]
What I'm doing here is a series of pairwise exchanges. By way of example, for [1,2,3,4,5,6], the first 6-2=4 steps (6 being the size of the array) alter the array as follows:
[1,2,3,4,6,5]
[1,2,3,6,4,5]
[1,2,6,3,4,5]
[1,6,2,3,4,5]
The 1, 6 and the 2 are in now the right positions. We repeat these steps, but this time only 6-4=2 times, to move the 5 and 3 into the correct positions:
[1,6,2,3,5,4]
[1,6,2,5,3,4]
The 4 is pushed to the end, it's correct position, so we are finished.

Whats the best way to split an array in ruby into multiple smaller arrays of random size

I have multiple arrays in ruby of variable length from 1 to 40 :
#items is a typical array which could be anywhere from 1 to 40 in length. eg
#items = [1, 2, 3, 4, 5, 6]
I want to randomly split the array into smaller arrays of lengths either 1, 2 or 3 to give a result of (for example)
#items = [[1, 2],[3],[4,5,6]]
or
#items = [[1],[2, 3],[4],[5,6]]
etc
I know you can split the array using #items.each_slice(3)... where 3 is a fixed length. But i want to randomly split large arrays of variable length into array sizes of 1,2 or 3 randomly... Whats the best way to achieve this?
items, #items = #items.dup, []
#items.push(items.shift(rand(1..3))) until items.empty?
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = []
until a.empty?
b << a.shift((1..a.size).to_a.sample)
end
# b => [[1, 2], [3, 4, 5, 6, 7], [8, 9], [10]]
# change everytime though
You can limit the sub arrays size by replacing the a.size with 3 or anything you want.
This solution maybe uses too many local variables, but it is non-destructive to the input array and flexible on array window maximum.
def rotateAndTake inputArray, windowSize
rotator, returnArray, breaker = 0, [], true
while breaker do
window = rand(windowSize)+1
if(rotator + window > inputArray.length) then
window = inputArray.length - rotator
breaker = false
end
returnArray << inputArray.rotate(rotator).take(window) if window > 0
rotator += window
end
returnArray
end
Also, I just wanted to write a solution that used the "rotate" method.
Just for yucks, I thought I'd try a pure functional form with no mutating methods for this problem:
( (0..#items.size)
.inject([0]) { |m,_| m + [m.last + 1 + rand(3)] }
.take_while { |i| i < #items.size } + [#items.size] ).
each_cons(2).
map { |s,e| #items[s...e] }
Here's another functional solution:
( [0]+
(1..a.length-1)
.to_a
.sample(rand(a.length))
.sort+
[a.length]
).each_cons(2).map{|i,j| a[i..j-1]}

How to drop the end of an array in Ruby

Array#drop removes the first n elements of an array. What is a good way to remove the last m elements of an array? Alternately, what is a good way to keep the middle elements of an array (greater than n, less than m)?
This is exactly what Array#pop is for:
x = [1,2,3]
x.pop(2) # => [2,3]
x # => [1]
You can also use Array#slice method, e.g.:
[1,2,3,4,5,6].slice(1..4) # => [2, 3, 4, 5]
or
a = [1,2,3,4,5,6]
a.take 3 # => [1, 2, 3]
a.first 3 # => [1, 2, 3]
a.first a.size - 1 # to get rid of the last one
The most direct opposite of drop (drop the first n elements) would be take, which keeps the first n elements (there's also take_while which is analogous to drop_while).
Slice allows you to return a subset of the array either by specifying a range or an offset and a length. Array#[] behaves the same when passed a range as an argument or when passed 2 numbers
this will get rid of last n elements:
a = [1,2,3,4,5,6]
n = 4
p a[0, (a.size-n)]
#=> [1, 2]
n = 2
p a[0, (a.size-n)]
#=> [1, 2, 3, 4]
regard "middle" elements:
min, max = 2, 5
p a.select {|v| (min..max).include? v }
#=> [2, 3, 4, 5]
I wanted the return value to be the array without the dropped elements. I found a couple solutions here to be okay:
count = 2
[1, 2, 3, 4, 5].slice 0..-(count + 1) # => [1, 2, 3]
[1, 2, 3, 4, 5].tap { |a| a.pop count } # => [1, 2, 3]
But I found another solution to be more readable if the order of the array isn't important (in my case I was deleting files):
count = 2
[1, 2, 3, 4, 5].reverse.drop count # => [3, 2, 1]
You could tack another .reverse on there if you need to preserve order but I think I prefer the tap solution at that point.
You can achieve the same as Array#pop in a non destructive way, and without needing to know the lenght of the array:
a = [1, 2, 3, 4, 5, 6]
b = a[0..-2]
# => [1, 2, 3, 4, 5]
n = 3 # if we want drop the last n elements
c = a[0..-(n+1)]
# => [1, 2, 3]
Array#delete_at() is the simplest way to delete the last element of an array, as so
arr = [1,2,3,4,5,6]
arr.delete_at(-1)
p arr # => [1,2,3,4,5]
For deleting a segment, or segments, of an array use methods in the other answers.
You can also add some methods
class Array
# Using slice
def cut(n)
slice(0..-n-1)
end
# Using pop
def cut2(n)
dup.tap{|x| x.pop(n)}
end
# Using take
def cut3(n)
length - n >=0 ? take(length - n) : []
end
end
[1,2,3,4,5].cut(2)
=> [1, 2, 3]

Ruby: Multiply all elements of an array

Let's say I have an array A = [1, 2, 3, 4, 5]
how can I multiply all elements with ruby and get the result? 1*2*3*4*5 = 120
and what if there is an element 0 ? How can I ignore this element?
This is the textbook case for inject (also called reduce)
[1, 2, 3, 4, 5].inject(:*)
As suggested below, to avoid a zero,
[1, 2, 3, 4, 5].reject(&:zero?).inject(:*)
There is also another way to calculate this factorial!
Should you want to, you can define whatever your last number is as n.
In this case, n=5.
From there, it would go something like this:
(1..num).inject(:*)
This will give you 120. Also, .reduce() works the same way.
Well, this is a dummy way but it works :)
A = [1, 2, 3, 4, 5]
result = 1
A.each do |i|
if i!= 0
result = result*i
else
result
end
end
puts result
If you want to understand your code later on, use this: Assume A = 5, I used n instead of A
n = 5
n.times {|x| unless x == 0; n = n * x; ++x; end}
p n
To carry it forward, you would:
A = [1,2,3,4,5]
arb = A.first
a = A.count
a.times {|x| arb = arb * A[x]; ++x}
p arb

Randomizing array elements

I have an array #number = [1,2,3,4,5,6,7,8,9]
Now, I want to randomize the array content... something like eg: [5,3,2,6,7,1,8]
Please guide me how to proceed with it.
Use the shuffle method ...
irb(main):001:0> [1,2,3,4,5].shuffle
=> [3, 4, 2, 5, 1]
the shuffle command returns a randomized version of an array
eg:
[1,2,3].shuffle => [2,3,1]
[1,2,3,4,5,6,7,8,9].sort_by {rand}[0,9]
=> [5, 7, 3, 8, 9, 4, 2, 1, 6]
If you are using old version of ruby... this will work
def randomize(array)
b = []
array.length.downto(1) { |n|
b.push array.delete_at(rand(n))
}
b
end
a = [1,2,3,4,5]
b=randomize(a)
print b
loop n times
i = random array index
j = random array index
swap elements i and j
end

Resources