How do I create a subset of an array based on an array of indexes for that array in Ruby - ruby

If I have an array like this:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
and I want to select a subset of that array based on this arbitrary array of indexes:
[0,1,4,7,8,13,14,15,18,19]
with the result being this subset of the first array:
[1,2,5,8,9,14,15,16,19,20]
My question is, how do I make a simple function (1 or 2 lines) out of the array of indexes and the starting array to get the subset?

arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
indexes = [0,1,4,7,8,13,14,15,18,19]
arr.values_at(*indexes) # => [1, 2, 5, 8, 9, 14, 15, 16, 19, 20]

arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
index = [0,1,4,7,8,13,14,15,18,19]
arr.select.with_index{|m,i| m if index.include? i}
#=> [1, 2, 5, 8, 9, 14, 15, 16, 19, 20]

arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
index = [0,1,4,7,8,13,14,15,18,19]
arr.each_with_index {|value,index| p value if indexes.include?(index)}

Related

How to merge arrays to one array kind of respectively in ruby

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]

Find largest element from multidimensional array of ints

I have an array of ints similar to this:
values = [[3, 4, 15, 16, 5, 13, 2], [1, 12, 13, 2, 10, -1], [11, 12, 1, 9, -2], [1, -10, -2, -13], [-11, -3, -14], [8, -3], [-11]]
How would I retrieve the index of the largest number, e.g. 16 == values[0][3]?
Don't sure I get you correct, but anyway:
1) If you need the largest element:
values.flatten.max
2) If you need largest element from each subarray:
values.map{|x| x.max}
UPD
About indexes:
largest_element = values.flatten.max
values.each_with_index do |e,i|
if e.include?(largest_element)
p i
values[i].each_with_index{|e, i| p i if e == largest_el}
end
end

count the number of consecutive integer elements in an array

Given I have an array such as follows:
arr = [8, 13, 14, 10, 6, 7, 8, 14, 5, 3, 5, 2, 6, 7, 4]
I would like to count the number of consecutive number sequences. Eg in the above array the consecutive number sequences (or array-slices) are:
[13,14]
[6,7,8]
[6,7]
And hence we have 3 such slices. What is an efficient Algorithm to count this? I know how I can do it O(N^2) but I'm looking for something which is better than that.
arr = [8, 13, 14, 10, 6, 7, 8, 14, 5, 3, 5, 2, 6, 7, 4]
p arr.each_cons(2).chunk{|a,b| a.succ == b || nil}.count #=> 3
nilhas a special meaning to the chunk-method: it causes items to be dropped.
arr = [8, 13, 14, 10, 6, 7, 8, 14, 5, 3, 5, 2, 6, 7, 4]
result = []
stage = []
for i in arr:
if len(stage) > 0 and i != stage[-1]+1:
if len(stage) > 1:
result.append(stage)
stage = []
stage.append(i)
print result
Output:
[[13, 14], [6, 7, 8], [6, 7]]
The time complexity of this code is O(n). (There's only one for loop. And it's not hard to see that each iteration in the loop is O(1).)
I would do as below using Enumerable#slice_before:
a = [8, 13, 14, 10, 6, 7, 8, 14, 5, 3, 5, 2, 6, 7, 4]
prev = a[0]
hash = Hash[a.slice_before do |e|
prev, prev2 = e, prev
prev2 + 1 != e
end.map{|e| [e,e.size] if e.size > 1}]
hash # => {[13, 14]=>2, [6, 7, 8]=>3, [6, 7]=>2}
hash.size # => 3
I think this can be done in O(N) time. If you just want the count,
Iterate through the array. Initialize counter to 0.
If next element is one more or one less than current element, increment the counter.
Continue iterating till the next element is not one more or one less than current element.
Repeat steps 2 and 3 until you reach the end.
If you want sections of continuously increasing consecutive elements (not clear from your question)
Iterate through the array. Initialize counter to 0.
If next element is one more than current element, increment the counter.
Continue iterating till the next element is not one more than current element.
Repeat steps 2 and 3 until you reach the end.

how to get an order-specified subset of an array of variable length from an array of variable length?

I have an array of objects of variable length n. Defined by the number of records in my database.
I need a function to grab subsets (keeping the objects in order and always beginning at index 0) of the array of specified length m where m can be any integer I pass in.
e.g. if n = 10 and m = 4
array foo = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
subset a = [0, 1, 2, 3]
subset b = [4, 5, 6, 7]
subset c = [8, 9]
So, I need to programmatically be able to say, "Give me the i-th subset of length m from an array, given the array is length n." Using the previous example: "Give me the second subset of length four from foo" => returns the items at positions [4, 5, 6, 7].
I hope that made sense. Assistance with a ruby solution would be much appreciated! thx!
foo.each_slice(subset_length).to_a[subset_index]
e.g. foo.each_slice(4).to_a[2] returns "the second subset of length four from foo".
You can use Enumerable#each_slice:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].each_slice(4).to_a
#=> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]]

How do I replace an array's element?

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.

Resources