Intersection of an arbitrary number of arrays - arrays

I need a function which takes an array of arrays as its argument, then returns the intersection of all the subarrays. How could I improve the following code, if at all?
class Array
def grand_intersection
if self.length > 1
filters = self[1..-1]
filters.reduce(self[0]) {|start, filter| start & filter}
else
self
end
end
end
P.S. I'm not too concerned about handling arrays whose content won't respond to #& -- the method won't be exposed to the user.

class Array
def grand_intersection
self.reduce :&
end
end
[[1,2,3,4,5], [2,3,4], [1,2,4,5]].grand_intersection
#=> [2, 4]

Related

looping through nested arrays and accessing elements RUBY

I want to iterate through a nested array and operate on each element, so square each number in this case. I know how to do it for a normal array but for some reason i am getting undefined map method when include deeper iteration to access the inner arrays. Am a newbie too so if you could explain how it works that would help my learning. Thanks
def SquareArrayElements(n)
n.each do |number|
number.map do |num|
squared_nums = num * num
end
end
squared_nums
end
SquareArrayElements([10,[[10],10],[10]])
Since you've said in the comments that:
i want to square the 10s and return them to one array =>[100,100,100,100].
I assume that you don't need to preserve the original arrays and just want one array with the squared results. If that's the case you can #flatten the array and then square the numbers:
def square_array(arr)
arr.flatten.map { |e| e ** 2 }
end
square_array([10,[[10],10],[10]])
#=> [100, 100, 100, 100]
You only need to call map on the arrays, not on the integers. That's why you're getting an undefined map method, integers don't support that method.
Try
def square_array(element)
if element.responds_to?(:map)
element.map{|m| square_array(m)}
else
element * element
end
end

How can I implement a chain method for my class?

I'm working with a string that has to be converted to a 2 dimensional array:
rows = [['1', '2'], ['10', '20']]
I need those values as integers instead of strings. I can iterate through them and then do map, like:
rows.each {|row| row.map!(&:to_i)}
I was trying to create a to_i method that could be chainable, so I can run rows.to_i.
def to_i
each do |nested|
nested.map!(&:to_i)
end
end
This unsurprisingly fails:
NoMethodError: undefined method `to_i' for [["1", "2"], ["10", "20"]]:Array
since Array doesn't implement the method. Besides monkey patching the Array class, is there a proper or more rubier way to do it?
The other alternative is doing:
def ary_to_i array
array.each do |nested|
nested.map!(&:to_i)
end
end
but I found the method call ary_to_i(rows) confusing.
You could define a to_i method just for rows:
rows = [['1','2'], ['10','20']]
def rows.to_i
each do |nested|
nested.map!(&:to_i)
end
end
p rows.to_i # => [[1, 2], [10, 20]]
Although it’s an anti-pattern, you might monkey-patch the Array class:
class Array
def to_i
map do |nested|
nested.map(&:to_i)
end
end
def to_i!
each do |nested|
nested.map!(&:to_i)
end
end
end
But I’d better go with the latter alternative in OP.
Sidenote: mutating arrays is not a best idea ever, but if you do, choose the name ending with a bang as in my example.

Return unique values of an array without using `uniq`

For a challenge, I'm trying to return the unique values of an array without using uniq. This is what I have so far, which doesn't work:
def unique
unique_arr = []
input_arr.each do |word|
if word != unique_arr.last
unique_arr.push word
end
end
puts unique_arr
end
input = gets.chomp
input_arr = input.split.sort
input_arr.unique
My reasoning here was that if I sorted the array first before I iterated through it with each, I could push it to unique_arr without repetition being a possibility considering if it's a duplicate, the last value pushed would match it.
Am I tackling this the wrong way?
Yes, you are making at least two mistakes.
If you want to call it as input_arr.unique with input_arr being an array, then you have to define the method on Array. You have input_arr within your method body, which comes from nowhere.
puts in the last line of your code outputs to the terminal, but makes the method return nil, which makes it behave differently from uniq.
It can be fixed as:
class Array
def unique
unique_arr = []
each do |word|
unique_arr.push(word) unless unique_arr.last == word
end
unique_arr
end
end
A unique array? That sounds like a Set to me:
require 'set'
Set.new([1,2,3,2,3,4]).to_a
#=> [1,2,3,4]
Here's a concise way to do it that doesn't explicitly use functionality from another class but probably otherwise misses the point of the challenge:
class Array
def unique
group_by(&:itself).keys
end
end
I try this three options. Just for challenge
class Array
def unique
self.each_with_object({}) { |k, h| h[k] = k }.keys
end
def unique2
self.each_with_object([]) { |k, a| a << k unless a.include?(k) }
end
def unique3
arr = []
self.map { |k| arr << k unless arr.include?(k) }
arr
end
end
Here is one more way to do this:
uniques = a.each.with_object([]) {|el, arr| arr << el if not arr.include?(el)}
That's so easy if you see it this way:
a = [1,1,2,3,4]
h = Hash.new
a.each{|q| h[q] = q}
h.values
and this will return:
[1, 2, 3, 4]

Ruby method to sum all values in a multidimensional array

I am trying to sum the elements of an array. WITHOUT using flatten. I have tried using the following:
def multi_array_sum(arr)
sum = 0
arr.each do |row|
row.each do |column|
sum += column
end
end
return sum
end
but unfortunately, it is not working. I am not sure how to iterate though a multidimensional array considering that I cannot use each if the first element in the array is not another array itself, for example, array = [[1, [1, 2], [3, 4, 5]].
If all elements are numeric or arrays, and you want to sum them all:
array.flatten.inject(:+)
Just use standard array functions and then enumerable.
array.flatten.reduce(:+)
If you are 100% sure that you cannot use flatten then you can use:
array.map { |a| a.reduce(:+) }.reduce(:+)
So if you absolutely can't use flatten (which is a bit weird), you can use a simple recursive method:
def multi_array_sum(arr)
case arr
when Fixnum
arr
when Array
arr.reduce(0) { |agg, sub_arr| agg + multi_array_sum(sub_arr) }
end
end
If each inner array is the same size and contains only numbers, you could use the method Matrix#[] to convert the array to a matrix, Matrix#each (without a block) to create an enumerator to generate the elements of the matrix, and Enumerable#reduce (aka inject) to compute the sum of all elements of the matrix.
require 'matrix'
def sum_all(arr)
Matrix[*arr].each.reduce(:+)
end
sum_all [[1,2],[3,4]] #=> 10

Define a trim method on Array that removes the first and last element

class Array
define_method(:trim) do
new_array = self.pop()
new_array = self.shift()
end
end
EDIT: What I tried (among other things)
["hi", "ho", "he"].trim()
This returns "hi".
Remove the last element. Remove the first element. But how do I get the method to return the remaining array instead of what's returned by .shift (or whatever happens to be the last instruction of the method)? Do I need another variable?
Thank you.
pop() and shift() will modify the array directly. You just need to tell the method to return self
class Array
define_method(:trim) do
self.pop()
self.shift()
self
end
end
EDIT : as this method can be dangerous, I suggest you define both trim! and trim. Where trim! will modify the array directly and trim return a copy of the array, trimmed
class Array
def trim!
self.pop()
self.shift()
self
end
def trim
self.dup.trim!
end
end
You can use range when accessing array elements, like that
ary = [1, 2, 3, 4]; ary[1..-2] #=> [2, 3]
So going back to the method, it can be:
class Array
def trim
self[1..-2]
end
end
[EDIT]: to avoid returning nil for empty arrays:
class Array
def trim
self[1..-2] || []
end
end

Resources