How can I substitue an element in an array?
a = [1,2,3,4,5]
I need to replace 5 with [11,22,33,44].flatten!
so that a now becomes
a = [1,2,3,4,11,22,33,44]
Not sure if you're looking to substitute a particular value or not, but this works:
a = [1, 2, 3, 4, 5]
b = [11, 22, 33, 44]
a.map! { |x| x == 5 ? b : x }.flatten!
This iterates over the values of a, and when it finds a value of 5, it replaces that value with array b, then flattens the arrays into one array.
Perhaps you mean:
a[4] = [11,22,33,44] # or a[-1] = ...
a.flatten!
A functional solution might be nicer, how about just:
a[0..-2] + [11, 22, 33, 44]
which yields...
=> [1, 2, 3, 4, 11, 22, 33, 44]
The version of bta using a.index(5) is the fastest one:
a[a.index(5)] = b if a.index(5) # 5.133327 sec/10^6
At least 10% faster than Ryan McGeary's one:
a.map!{ |x| x == 5 ? b : x } # 5.647182 sec/10^6
However, note that a.index(5) only return the first index where 5 is found.
So, given an array where 5 appears more than once, results will be different:
a = [1, 2, 3, 4, 5, 5]
b = [11,22,33,44]
a[a.index(5)] = b if a.index(5)
a.flatten # => [1, 2, 3, 4, 11, 22, 33, 44, 5]
a.map!{ |x| x == 5 ? b : x }
a.flatten # => [1, 2, 3, 4, 11, 22, 33, 44, 11, 22, 33, 44]
Array#delete will return the item or nil. You may use this to know whether or not to push your new values
a.push 11,22,33,44 if a.delete 5
You really don't have to flatten if you just concatenate. So trim the last element off the first array and concatenate them:
a = [ 1, 2, 3, 4, 5 ] #=> [1, 2, 3, 4, 5]
t = [11, 22, 33, 44] #=> [11, 22, 33, 44]
result = a[0..-2] + t #=> [1, 2, 3, 4, 11, 22, 33, 44]
a[0..-2] is a slice operation that takes all but the last element of the array.
Hope it helps!
This variant will find the 5 no matter where in the array it is.
a = [1, 2, 3, 4, 5]
a[a.index(5)]=[11, 22, 33, 44] if a.index(5)
a.flatten!
Here is another simple way to replace the value 5 in the array:
a[-1, 1] = [11, 22, 33, 44]
This uses the Array#[]= method. I'm not exactly sure why it works though.
gweg, not sure what you're trying to do here, but are you looking for something like this?
a = [1, 2, 3, 4, 5]
a.delete_at(4)
a = a.concat([11,22,33,44])
There are a number of ways of doing this -- I don't think the code above is especially nice looking. It all depends on the significance of '5' in your original array.
Related
I want to combine the arrays together to add the first column of all arrays, then the second columns, respectively, to the end.
My arrays :
[1,2,3,4,5]
[6,7,8,9,10]
[11,12,13,14,15]
i want result :
[1,6,11 , 2,7,12 , 3,8,13 , 4,9,14 , 5,10,15]
Suppose we have a "simple" case where the three arrays are the same length:
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = [11,12,13,14,15]
In this case, you can use Array#zip to merge the arrays in your desired way, then flatten the result into a single array:
a.zip(b, c).flatten
#=> [1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14, 5, 10, 15]
However, what if a.length > b.length or b.length > c.length?
a = [1,2,3,4,5]
b = [6,7,8,9]
c = [10,11,12]
This is a little bit harder, because now Array#zip will leave you with some nil values that you presumably want to remove:
a.zip(b, c).flatten
#=> [1, 6, 10, 2, 7, 11, 3, 8, 12, 4, 9, nil, 5, nil, nil]
a.zip(b, c).flatten.compact
#=> [1, 6, 10, 2, 7, 11, 3, 8, 12, 4, 9, 5]
And finally, what if a.length < b.length or b.length < c.length?
a = [1,2,3]
b = [4,5,6,7]
c = [8,9,10,11,12]
This is again a bit harder. Now, you'll presumably want to pad the arrays with as many nils as needed, and then perform the same operation as above:
max_length = [a,b,c].map(&:length).max
def padded_array(array, size)
array.dup.fill(nil, array.length, size)
end
padded_array(a, max_length).zip(
padded_array(b, max_length), padded_array(c, max_length)
).flatten.compact
So the complexity of your final answer depends on what arrays you are dealing with, and how far you need to go with accounting for edge cases.
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = [11,12,13,14,15]
((a.zip b).zip c).flatten.compact
=> [1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14, 5, 10, 15]
This is what I am trying to get:
Array1=[a,b,c]
Array2=[d,e,f]
=> [a*d,a*e,a*f,b*d,b*e,b*f,c*d,c*e,c*f]
How can you do this in ruby? So far I can only return [a*d,b*e,c*f]
Read Array#product method.
array1 = [1, 2, 3]
array2 = [3, 5, 6]
array1.product(array2).map { |a, b| a * b }
# => [3, 5, 6, 6, 10, 12, 9, 15, 18]
Array1.product(Array2).map{|x, y| x * y}
I know the idiomatic way to do a for loop in Ruby is to use an Enumerator like .each, but I'm running into a problem: I'd like to iterate over a subset of an Array and modify those elements. Calling .map! with a subset like ary[0..2] or .slice(0..2) doesn't seem to do it; presumably because that slicing operator is creating a new Array?
Desired behavior with for instead of iterator:
iter_ind = [2,3,4]
my_ary = [1,3,5,7,9,11]
for j in iter_ind
my_ary[j] = my_ary[j] + 1
# some other stuff like an exchange operation maybe
end
=> [1, 3, 6, 8, 10, 11]
Things that don't work:
irb(main):032:0> ar[2..4].map! {|el| el = el+1}
=> [6, 8, 10]
irb(main):033:0> ar
=> [1, 3, 5, 7, 9, 11]
irb(main):034:0> ar.slice(2..4).map! {|el| el = el+1}
=> [6, 8, 10]
irb(main):035:0> ar
=> [1, 3, 5, 7, 9, 11]
irb(main):036:0> ar[2..4].collect! {|el| el = el+1}
=> [6, 8, 10]
irb(main):037:0> ar
=> [1, 3, 5, 7, 9, 11]
Try this.
In example below I implemented something that could be named map_with_index. each_with_index if no block given returns iterator. I use it to map our array.
ary = [1, 3, 5, 7, 9, 11]
ary.each_with_index.map { |elem, index| index.between?(2, 4) ? elem += 1 : elem }
# => [1, 3, 6, 8, 10, 11]
You may also try the following:
?> ary = [1, 3, 5, 7, 9, 11]
=> [1, 3, 5, 7, 9, 11]
?> ary.map!.with_index {|item, index| index.between?(2, 4) ? item += 1 : item}
=> [1, 3, 6, 8, 10, 11]
?> ary
=> [1, 3, 6, 8, 10, 11]
You could use Array#each_index if you don't mind referencing the array twice:
ary = [1, 3, 5, 7, 9, 11]
ary.each_index { |i| ary[i] += 1 if i.between? 2, 4 }
#=> [1, 3, 6, 8, 10, 11]
Or if you don't want to iterate the whole array, this would work, too:
ary = [1, 3, 5, 7, 9, 11]
ary[2..4] = ary[2..4].map { |el| el + 1 }
ary
#=> [1, 3, 6, 8, 10, 11]
I have an array:
arr = [1,1,2,3,5,8,13,21,34]
I'd like to filter the array in the same way as select but also separately gather all the elements that fail the condition:
[evens, odds] = arr.split_filter {|p| p % 2 == 0}
# evens = [2, 8, 34]
# odds = [1, 1, 3, 5, 13, 21]
I could do
evens = arr.select {|p| p % 2 == 0}
odds = arr.select {|p| p % 2 != 0}
But that seems inefficient. Does anyone know of a function that works like split_filter?
You're looking for Enumerable#partition:
arr = [1,1,2,3,5,8,13,21,34]
evens, odds = arr.partition{|a| a % 2 == 0}
evens # => [2, 8, 34]
odds # => [1, 1, 3, 5, 13, 21]
Or, shorter version:
evens, odds = arr.partition(&:even?)
We could always use Enum#group_by for the same.
arr = [20,1,1,2,3,5,8,13,21,34]
even,odd = arr.group_by(&:even?).values_at(true,false)
even #=> [20, 2, 8, 34]
odd #=> [1, 1, 3, 5, 13, 21]
I need a ruby formula to create an array of integers. The array must be every other 2 numbers as follows.
[2, 3, 6, 7, 10, 11, 14, 15, 18, 19...]
I have read a lot about how I can do every other number or multiples, but I am not sure of the best way to achieve what I need.
Here's an approach that works on any array.
def every_other_two arr
arr.select.with_index do |_, idx|
idx % 4 > 1
end
end
every_other_two((0...20).to_a) # => [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
# it works on any array
every_other_two %w{one two three four five six} # => ["three", "four"]
array = []
#Change 100000 to whatever is your upper limit
100000.times do |i|
array << i if i%4 > 1
end
This code works for any start number to any end limit
i = 3
j = 19
x =[]
(i...j).each do |y|
x << y if (y-i)%4<2
end
puts x
this should work
For fun, using lazy enumerables (requires Ruby 2.0 or gem enumerable-lazy):
(2..Float::INFINITY).step(4).lazy.map(&:to_i).flat_map { |x| [x, x+1] }.first(8)
#=> => [2, 3, 6, 7, 10, 11, 14, 15]
here's a solution that works with infinite streams:
enum = Enumerator.new do |y|
(2...1/0.0).each_slice(4) do |slice|
slice[0 .. 1].each { |n| y.yield(n) }
end
end
enum.first(10) #=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
enum.each do |n|
puts n
end
Single Liner:
(0..20).to_a.reduce([0,[]]){|(count,arr),ele| arr << ele if count%4 > 1;
[count+1,arr] }.last
Explanation:
Starts the reduce look with 0,[] in count,arr vars
Add current element to array if condition satisfied. Block returns increment and arr for the next iteration.
I agree though that it is not so much of a single liner though and a bit complex looking.
Here's a slightly more general version of Sergio's fine answer
module Enumerable
def every_other(slice=1)
mod = slice*2
res = select.with_index { |_, i| i % mod >= slice }
block_given? ? res.map{|x| yield(x)} : res
end
end
irb> (0...20).every_other
=> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
irb> (0...20).every_other(2)
=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
irb> (0...20).every_other(3)
=> [3, 4, 5, 9, 10, 11, 15, 16, 17]
irb> (0...20).every_other(5) {|v| v*10 }
=> [50, 60, 70, 80, 90, 150, 160, 170, 180, 190]