Get k-1 length subset arrays of k length array [duplicate] - ruby

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
ruby array element grouping
Example. Given array a:
a = [1, 2, 3]
Its length is 3 so I want to print all 2-length arrays. These are:
[1, 2]
[1, 3]
[2, 3]
I don't know if there is some method in Ruby to get subset arrays. If there is not such a method what is most efficient way to do achieve this.

That's just a simple combination of 2 elements:
>> xs = [1, 2, 3]
>> xs.combination(xs.size - 1).to_a
=> [[1, 2], [1, 3], [2, 3]]
[EDIT] As #Joshua pointed out in a comment, the docs state that the order is not guaranteed (!). So here is a functional implementation that generates the combinations in the order you asked for. For completeness, I'll make it lazy as the original combination method:
require 'enumerable/lazy'
class Array
def combinations_of(n)
if n == 0
[[]].lazy
else
0.upto(self.size - 1).lazy.flat_map do |idx|
self.drop(idx + 1).combinations_of(n - 1).map do |xs|
[self[idx]] + xs
end
end
end
end
end

Related

How to find the sum of each row for a multi-dimensional array

I would like to find the sum of each row of a multidimensional array, and have the sums an array, e.g., for [[1,2,3],[1,1,1]], I would like to get [6,3].
I tried the following:
arr = [[1,2,3],[3,2,1],[2,1,3]]
print arr.each{|row| row.each{|column| puts column}}
Results:
1
2
3
3
2
1
2
1
3
[[1, 2, 3], [3, 2, 1], [2, 1, 3]]
I am struggling with it. I still don't fully understand each iterators. Any help would be appreciated.
For ruby 2.4.0 or newer
a.map { |suba| suba.sum }
or simply
a.map(&:sum)
for ruby prior to 2.4.0
a.map { |suba| suba.inject(0, :+) }
[[1,2,3],[1,1,1]].map{|a| a.inject(:+)} # => [6, 3]
If there is a possibility that any of the sub-array can be empty, then you need to add the initial 0, as Ursus pointed out.
[[1,2,3],[1,1,1]].map{|a| a.inject(0, :+)} # => [6, 3]
[[1,2,3],[1,1,1]].map { |a| a.inject(0, :+) } # => [6 , 3]
map changes each element to the return value of this elements block
get the sum for each array with inject(:+)
use inject(0, :+) to set 0 instead of the first element as the start value (handles empty inner array)
see:
Enumerable#inject
Enumerable#map
"How to find the sum of each row"
arr = [[1,2,3], [1,1,1]]
print arr.each{|row| <-- here you have each row
So now row contains [1,2,3] initially. As others have mentioned, you can apply a sum here. (You don't need the leading print).
arr.each{|row| puts row.sum}
Result:
6
3
But a better way to do it is with map. As I told a Ruby newbie many years ago, think of map when you want to change every element to something else, in other words a "1:1 mapping" of input to output. In this case the output is row.sum:
sums = arr.map{|row| row.sum}
Result:
[6, 3]

What does the "*" mean in this recursive ruby function? [duplicate]

This question already has answers here:
What does the (unary) * operator do in this Ruby code?
(3 answers)
What does the * (star) mean in Ruby? [duplicate]
(1 answer)
Closed 7 years ago.
I read this code that is about quicksort with monkey-patching for the Array class.
class Array
def quicksort
return [] if empty?
pivot = delete_at(rand(size))
left, right = partition(&pivot.method(:>))
return *left.quicksort, pivot, *right.quicksort
end
end
I don't know what the star (*) sign seen at the start of *left.quicksort is. Can't we just use left.quicksort?
The star (in this case) stands for array unpacking. The idea behind it is that you want to get one array with the given elements, instead of array of array, element, array:
left = [1, 2, 3]
pivot = 4
right = [5, 6, 7]
[left, pivot, right] # => [[1, 2, 3], 4, [5, 6, 7]]
[*left, pivot, *right] # => [1, 2, 3, 4, 5, 6, 7]
The * takes a list of arguments and splits them into individual elements.
This allows you to return one un-nested array even when the left and right themselves return an array.
Regarding can't we just use left.quicksort did you give it a try?
def a()
return *[1,2,3], 4, *[5,6]
end
def b()
return [1,2,3], 4, *[5,6]
end
b()
=> [[1, 2, 3], 4, 5, 6]
a()
=> [1, 2, 3, 4, 5, 6]
Without the asterisk, you will have three values returned... the first and last value will be a single array with multiple values
[array1], pivot, [array2]
With the asterisk, the array values will be returned as separate components...
array1_value_1, array1_value_2, array1_value_3, ..., pivot, array2_value_1, array2_value2, array2_value_3, ...

How do I explode an internal array in Ruby if the internal count is less than a certain value?

Using Ruby 2.1, if I have an array like:
[[1,1], [2,3], [5,8], [6, 4]]
How can I convert that to an array that only has internal arrays with a count > 3?
For example, it should be:
[1, 2, 2, 2, [5,8], [6,4]]
So [5,8] and [6,4] would "pass" because their counts are > 3 but [1,1] and [2,3] would "fail" and explode out because their counts are < than 4.
EDIT
Sorry, I wasn't very clear. By "counts" I mean the second value in the internal arrays. For example, the [2,3] would have a value of 2 and a count of 3. [5,8] would have a value of 5 and a count of 8.
So if the count is > 3 then keep the original array. If the count is 3 or less, then explode the value out count number of times.
I'm pretty sure someone can come up with a better way of doing this, but:
input = [[1,1], [2,3], [5,8], [6, 4]]
input.flat_map {|val, ct| ct > 3 ? [[val, ct]] : Array.new(ct, val) }
# => [1, 2, 2, 2, [5, 8], [6, 4]]
The basic idea is that we just map the inputs (each entry) to an output (the original entry or an exploded list of values) by the count. I'm using flat_map here, but you could use the same technique with map {}.flatten(1) if you wanted. You could also use inject or each_with_object to collect the output values, which may be more straightforward but slightly less terse.
Try this:
data = [[1,1], [2,3], [5,8], [6, 4]]
results = []
data.each do |arr|
val, count = arr
if count > 3
results << arr
else
results.concat [val] * count
end
end
p results
--output:--
[1, 2, 2, 2, [5, 8], [6, 4]]
arr = [[1,1], [2,3], [5,8], [6, 4]]
arr.flat_map { |a| (a.last > 3) ? [a] : [a.first]*a.last }
#=> [1, 2, 2, 2, [5, 8], [6, 4]]
Thanks to #ChrisHeald for pointing out that flat_map is equivalent to map {}.flatten(1) (I previously had the latter) and to #7stud for telling me my original solution was incorrect, which gave me the opportunity to make my solution more interesting as well as (hopefully) correct.

Adding two arrays in Ruby when the array length will always be the same

So, I need to add two arrays together to populate a third. EG
a = [1,2,3,4]
b = [3,4,5,6]
so that:
c = [4,6,8,10]
I read the answer given here: https://stackoverflow.com/questions/12584585/adding-two-ruby-arrays
but I'm using the codecademy labs ruby editor and it's not working there, plus the lengths of my arrays are ALWAYS going to be equal. Also, I don't have any idea what the method ".with_index" is or does and I don't understand why it's necessary to use ".to_i" when the value is already an integer.
It seems like this should be really simple?
a = [1,2,3,4]
b = [3,4,5,6]
a.zip(b).map { |i,j| i+j } # => [4, 6, 8, 10]
Here
a.zip(b) # => [[1, 3], [2, 4], [3, 5], [4, 6]]
and map converts each 2-tuple to the sum of its elements.
OPTION 1:
For a pure Ruby solution, try the transpose method:
a = [1,2,3,4]
b = [3,4,5,6]
c = [a, b].transpose.map{|x, y| x + y}
#=> [4,6,8,10]
OPTION 2:
If you're in a Rails environment, you can utilize Rails' sum method:
[a, b].transpose.map{|x| x.sum}
#=> [4,6,8,10]
EXPLANATION:
transpose works perfectly for your scenario, since it raises an IndexError if the sub-arrays don't have the same length. From the docs:
Assumes that self is an array of arrays and transposes the rows and columns.
If the length of the subarrays don’t match, an IndexError is raised.

Add two arrays into another array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
ruby: sum corresponding members of two arrays
So I'm struggling to do this.
I am trying to add two arrays and put the results into a third one. Now I want to be able to do this through a function though.
So I have Array_One, Array_Two, and Array_Three.
I would want to call the "compare function" to one and two and make Three that length and then if they the lengths matched I would want to add One and Two and put the results in three.
Could this be done in one function?
Better way to do this?
That's my thought process but I don't have the knowledge of Ruby to do this.
EDIT:
Sorry for the vagueness.
Array_One = [3,4]
Array_Two = [1,3]
Array_Three= []
I would want to pass One and Two through a function that compares the length and verifies they're the same length.
Then I would, in my mind, send it through a function that actually does the adding.
So in the end I would have Array_Three = [4,7]
Hope that helps.
Your question's description is little confusing, but I think this may be what you want:
def add_array(a,b)
a.zip(b).map{|pair| pair.reduce(&:+) }
end
irb> add_array([1,2,3],[4,5,6])
=> [5, 7, 9]
In addition it generalize to add multiple arrays quite easily:
def add_arrays(first_ary, *other_arys)
first_ary.zip(*other_arys).map{|column| column.reduce(&:+) }
end
irb> add_arrays([1,2,3],[4,5,6])
=> [5, 7, 9]
irb> add_arrays([1,2,3],[4,5,6],[7,8,9])
=> [12, 15, 18]
One possible method (without any checks) assuming I understood your question:
x = [1, 2, 3]
y = [4, 5, 6]
z = []
x.each_with_index do |v, i|
z << v + y[i]
end
Another method (still assuming I understood the question):
[x, y].transpose.map {|v| v.reduce(:+)}
If by add you mean element-wise addition than you can use:
def add(a, b)
a.zip(b).map &:sum
end
assuming your environment has sum defined.
Sum is an alias for reduce(&:+), which you can use instead.
zip is a function that takes two arrays and returns an array of arrays:
[a1, a2, a3, ..., an].zip [b1, b2, b3, ..., bm]
#=> [[a1, b1], [a2, b2], [a3, b3], ..., [an, bn]]
# assuming n <= m
We than take our array of arrays and sum all numbers in that array together and than collect the results with map.
map is a function that takes a block and produces an array:
[c1, c2, c3, ..., cn].map &block
# => [block.call(c1), block.call(c2), block.call(c3), ..., block.call(cn)]
So if we get example input say
a = [1, 2, 3]
b = [4, 2, 5]
a.zip(b) #=> [[1,4], [2,2], [3,5]]
a.zip(b).map(&:sum) #=> [[1,4].sum, [2,2].sum, [3,5].sum] #=> [5, 4, 8]
Now we can check that the same length by using an if condition:
def add(a, b)
a.zip(b).map &:sum if a.size == b.size
end
If you want to add two arrays, you can simply add them:
array1 = [1, 2, 3]
array2 = ['a', 'b', 'c']
if array1.length == array2.length
array3 = array1 + array2
end
# array3 = [1, 2, 3, 'a', 'b', 'c']

Resources