Get the exact differences of two arrays - ruby

I have two arrays:
array1 = [1,2,2,4,5,6]
array2 = [2,1]
How do I get
array3 = [2,4,5,6]
I have tried array1 - array2, but it returns [4,5,6].

What you are describing is a multiset. There is no implementation in the standard library, but you can use the multiset gem.
require 'multiset'
ms1 = Multiset.new([1, 2, 2, 4, 5, 6])
ms2 = Multiset.new([2, 1])
ms1 - ms2
#=> #<Multiset:#1 2, #1 4, #1 5, #1 6>
(ms1 - ms2).to_a
#=> [2, 4, 5, 6]

You could find each element's index and delete that one, as shown in this answer:
array1 = [1,2,2,4,5,6]
array2 = [2,1]
array2.each { |obj| array1.delete_at(array1.index(obj) || array1.length) }
array1 #=> [2, 4, 5, 6]

Related

How do I add together two arrays and get the result back as one number? Ruby

I need to add together two arrays of numbers and print the result as a total number.
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
arr1 + arr2
Just gives me = 1 2 3 4 5 6, but I want 21.
you can use the sum method
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
(arr1 + arr2).sum
This is another way
arr1 = [1, 2, 3]
arr2 = [4, 5, 6]
p (arr1 + arr2).reduce(:+)
Output
21

Duplicate elements of array in ruby

I find a lot of reference about removing duplicates in ruby but I cannot find how to create duplicate.
If I have an array like [1,2,3] how can I map it to an array with dubbed items? [1,1,2,2,3,3]
Is there a method?
Try this one
[1, 2, 3].flat_map { |i| [i, i] }
=> [1, 1, 2, 2, 3, 3]
Here's yet another way, creating the array directly with Array#new :
array = [1, 2, 3]
repetitions = 2
p Array.new(array.size * repetitions) { |i| array[i / repetitions] }
# [1, 1, 2, 2, 3, 3]
According to fruity, #ursus's answer, #ilya's first two answers and mine have comparable performance. transpose.flatten is slower than any of the others.
#Ursus answer is the most clean, there are possible solutions:
a = [1, 2, 3]
a.zip(a).flatten
#=> [1, 1, 2, 2, 3, 3]
Or
a.inject([]) {|a, e| a << e << e} # a.inject([]) {|a, e| n.times {a << e}; a}
=> [1, 1, 2, 2, 3, 3]
Or
[a, a].transpose.flatten # ([a] * n).transpose.flatten
=> [1, 1, 2, 2, 3, 3]
Try this:
[1, 2, 3] * 2
=> [1, 2, 3, 1, 2, 3]
You might want it sorted:
([1, 2, 3] * 2).sort
=> [1, 1, 2, 2, 3, 3]

How can I modify an array without destroying an array assigned to it?

Consider the following:
array1 = [1, 2, 3, 4]
array2 = array1 # => [1, 2, 3, 4]
array2.pop
array2 # => [1, 2, 3]
array1 # => [1, 2, 3]
Why is array1 destroyed when I've only called pop on array2? Is there a way to pop the last value from array2 and leave array1 intact so that I get array1 # => [1, 2, 3, 4]?
It's an aliasing issue. Your references point to the same Array object in memory. If your arrays contain simple Integers like those dup method do the trick.
array2 = array1.dup
array2 = array1.dup
array2 = array1.clone => Your changes effects both arrays
I prefer Object#dup method, but here is one more option FYI:
> array1 = [1, 2, 3, 4]
#=> [1, 2, 3, 4]
> array2 = Array.new + array1
#=> [1, 2, 3, 4]
> array1.object_id
#=> 87422520
> array2.object_id
#=> 87400390

Returning all maximum or minimum values that can be multiple

Enumerable#max_by and Enumerable#min_by return one of the relevant elements (presumably the first one) when there are multiple max/min elements in the receiver. For example, the following:
[1, 2, 3, 5].max_by{|e| e % 3}
returns only 2 (or only 5).
Instead, I want to return all max/min elements and in an array. In the example above, it would be [2, 5] (or [5, 2]). What is the best way to get this?
arr = [1, 2, 3, 5]
arr.group_by{|a| a % 3} # => {1=>[1], 2=>[2, 5], 0=>[3]}
arr.group_by{|a| a % 3}.max.last # => [2, 5]
arr=[1, 2, 3, 5, 7, 8]
mods=arr.map{|e| e%3}
find max
max=mods.max
indices = []
mods.each.with_index{|m, i| indices << i if m.eql?(max)}
arr.select.with_index{|a,i| indices.include?(i)}
find min
min = mods.min
indices = []
mods.each.with_index{|m, i| indices << i if m.eql?(min)}
arr.select.with_index{|a,i| indices.include?(i)}
Sorry for clumsy code, will try to make it short.
Answer by #Sergio Tulentsev is the best and efficient answer, found things to learn there. +1
This is the hash equivalent of #Serio's use of group_by.
arr = [1, 2, 3, 5]
arr.each_with_object(Hash.new { |h,k| h[k] = [] }) { |e,h| h[e%3] << e }.max.last
#=> [2, 5]
The steps:
h = arr.each_with_object(Hash.new { |h,k| h[k] = [] }) { |e,h| h[e%3] << e }
#=> {1=>[1], 2=>[2, 5], 0=>[3]}
a = h.max
#=> [2, [2, 5]]
a.last
#=> [2, 5]

Replace from one array values of another array

I have two arrays:
array1 = [3, 4, 4, 5, 6, 7, 8, 8]
array2 = [4, 5, 8, 8]
I want to remove those elements of array1, which are found in array2, but only in one instance. The resulting array, array3, must be like this:
array3 = [3, 4, 6, 7]
I tried:
array3 = array1 - array2
but the result was unsatisfactory:
array3 -> [3, 6, 7]
This may not be the most efficient way of doing what you want, but it works:
array1 = [3, 4, 4, 5, 6, 7, 8, 8]
array2 = [4, 5, 8, 8]
array2.each do |item|
index = array1.index item
array1.delete_at index if index
end
A non-imperative just to show other ways of doing things. Using Facets (just for convenience to get the histogram), I'd write this. O(n):
require 'facets'
array3 = array1.reduce([array2.frequency, []]) do |(h, output), x|
if h[x] && h[x] > 0
[h.update(x => h[x] - 1), output]
else
[h, output << x]
end
end[1]
#=> [3, 4, 6, 7]
To make the snippet purely functional you would use Hash#merge/Array#+ instead of Hash#update/Array:<<, but due to the nature of these data structures it would be terribly inefficient.

Resources