-3

I have my two arrays

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

y = [2, 4]

and I want to find the items from my array x that are divisible by the items of my array y, and create a new array with result numbers. In this case [4, 8, 12, 16, 18]. I want to find a code that could work with different arrays length with different numbers, not only with the numbers of the example above.

  • 2
    _"I want to find a code"_, but, have you tried something? – Sebastián Palma May 17 '20 at 05:16
  • I have tried with the .find method but I didn't find a way to divide the items by the items of the second array, one by one. I tried something like this: x.find {|item| item % ... (here is where I get stuck) = 0} – Emilio Contreras May 17 '20 at 06:42
  • 1
    Do you mean divisible for all the items in `y`? Is that the case for `18`? – Sebastián Palma May 17 '20 at 07:02
  • What is the code you are having trouble with? What trouble do you have with your code? Do you get an error message? What is the error message? Is the result you are getting not the result you are expecting? What result do you expect and why, what is the result you are getting and how do the two differ? Is the behavior you are observing not the desired behavior? What is the desired behavior and why, what is the observed behavior, and in what way do they differ? Please, provide a [mre]. Please be aware that [so] is not a code-writing service, you need to show your efforts! – Jörg W Mittag May 17 '20 at 09:38

2 Answers2

2

Suppose the arrays were as follows.

x = [12, 24, 36, 54, 72, 96, 108] 
y = [12, 9]

We can see that the elements of x that are divisible by all elements of y are:

[36, 72, 108]

To obtain this array efficiently we may first convert each element of y to its prime divisors:

require 'prime'

ypd = y.map { |n| Prime.prime_division(n) }
  #=> [[[2, 2], [3, 1]], [[3, 2]]] 

See Prime::prime_division

Consider, for example, the prime divisors of 12. We see that they are given by the array

[[2, 2], [3, 1]]

That simply means that

(2**2)*(3**1) #=> 4*3 #=> 12

We observe that for an element of x to be divisible by both elements of y it must be divisible by the single number whose prime divisors are given by

[[2, 2], [3, [1, 2].max]] #=> [[2, 2], [3, 2]]

which is

(2**2)*(3**2) #=> 36

By extension, we can simply combine all the elements of y into a single number, regardless of the size of y. That could do that as follows.

h = ypd.each_with_object({}) do |a,h|
  a.each do |prime,count|
    h.update(prime => count) { |_,o,n| [o,n].max }
  end
end  
  #=> {2=>2, 3=>2}

That single number is therefore:

z = h.reduce(1) { |n,(prime,count)| n*(prime**count) }
  #=> 36

Lastly, we can select the elements of interest from x:

x.select { |n| (n % z).zero? }
  #=> [36, 72, 108]
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • 1
    You can also get 36 via `[12, 9].inject(:lcm)` (although it might be slower than prime factorization depending on the input) – Stefan May 18 '20 at 07:09
  • 1
    @Stefan, perhaps `lcm` should be changed from `lcm(n)` to `lcm(*args)`. – Cary Swoveland May 18 '20 at 07:24
  • Yes, that would be useful (admittedly, I'm not a huge fan of Ruby's `first.something(*rest)` approach – IMO these should be _class_ methods, e.g. `Array.union(foo, bar, baz)` instead of `foo.union(bar, baz)`, same for `product`, `concat`, `zip`, etc.) – Stefan May 18 '20 at 09:15
0

I would suggest this

x.each_with_object([]) do |i, new_array|
  new_array << i if divisible_by_arrays_members(y, i)
end

Method divisible_by_arrays_members:

def divisible_by_arrays_members(array, number)
  array.each { |i| return false if number % i != 0 }
end
Ruslan Valeev
  • 1,529
  • 13
  • 24