Remove duplicates from nested array - ruby

I have an Array of Arrays that contains numbers in a particular order. I want to remove the duplicates out of the nested arrays, but there is a hierarchy: If a number occurs in a lower-index of the array, remove all duplicates down the Array chain.
Example:
nums = [[10, 6, 14], [6], [10, 6, 9], [10, 13, 6], [10, 13, 6, 9, 16], [10, 13]]
nums[0] contains [10,6,14] so any subsequent mention of 10,6,14 should be removed from the other arrays in the chain, meaning nums[2] should have 10,6 removed and only 9 should remain.
I'm having trouble doing this with nested loops, can any Ruby wizards help please?

This should do it:
input = [[10, 6, 14], [6], [10, 6, 9], [10, 13, 6], [10, 13, 6, 9, 16], [10, 13]]
seen = []
output = input.map do |numbers|
new = numbers.uniq - seen
seen += new
new
end
# => output is [[10, 6, 14], [], [9], [13], [16], []]
If you want to remove the empty lists in the output, simply
output.reject!(&:empty?)

require 'set'
nums = [[10, 6, 14], [6], [10, 6, 9], [10, 13, 6], [10, 13, 6, 9, 16], [10, 13]]
found = Set.new
new_nums = []
for subarray in nums do
sub_new = []
for i in subarray do
if not found.member? i
sub_new << i
end
found << i
end
new_nums << sub_new
end
puts(nums.inspect)
puts(new_nums.inspect)

Yet another way. It keeps original order of elements in arrays:
require 'set'
nums = [[10, 6, 14], [6], [10, 6, 9], [10, 13, 6], [10, 13, 6, 9, 16], [10, 13]]
nums2 = nums.inject([[], Set.new]) do |(output, seen), ary|
[output << ary.reject { |a| seen.include?(a) }, seen.union(ary)]
end[0]
p nums2
# [[10, 6, 14], [], [9], [13], [16], []]

Is the following incorrect? Should the [6] be removed or not?
nums = [[10, 6, 14], [6], [10, 6, 9], [10, 13, 6], [10, 13, 6, 9, 16], [10, 13]]
def remove_duplicate_numbers( array )
seen = []
array.map{ |sub_array|
result = sub_array - seen
seen += sub_array
result
}
end
p remove_duplicate_numbers( nums )
#=> [[10, 6, 14], [], [9], [13], [16], []]
If this is not what you want, please post the actual output you expect for your array.

Related

How do I make a hash out of many arrays?

I have an array that looks like this:
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
How would I turn that into a hash that looks similar to this:
{1=>[6, 11], 2=>[7, 12], 3=>[8, 13], 4=>[9, 14], 5=>[10, 15]]
Any help would be appreciated! Trying to do this in Ruby.
foo = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
foo.transpose.map { |x, *y| [x, y] }.to_h
That's a really strange way of mapping things, but with a clever method signature it's not too hard:
def pivot(keys, *values)
keys.each_with_index.map do |key, i|
[ key, values.map { |v| v[i] } ]
end.to_h
end
Then you'd call it with a splat:
a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
pivot(*a)
# => {1=>[6, 11], 2=>[7, 12], 3=>[8, 13], 4=>[9, 14], 5=>[10, 15]}
I kind of like zip:
a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
a[0].zip(a[1].zip(a[2])).to_h
The downside is that it's hardwired for three subarrays.
This can be generalized with a splat, so
a = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]
a[0].zip(a[1].zip(*a.drop(2))).to_h
yields
{1=>[6, 11, 16], 2=>[7, 12, 17], 3=>[8, 13, 18], 4=>[9, 14, 19], 5=>[10, 15, 20]}
without any additional levels of zipping required.
Let's say your array is stored under the variable name array I would go about it like this:
hash = {}
array[0].each.with_index do |value, i|
hash[value] = [array[1][i], array[2][i]]
end
A kind of mixture of pjs and ndn's answers:
arr.first.zip(arr[1..-1].transpose).to_h
Also very similarly (posted by CarySwoveland) in comments:
arr.first.zip(arr.drop(1).transpose).to_h

Find and return the longest array in a nested array with its size

I want to write a function that takes in a nested array and return the size of the longest array and itself.
max_with_size([]) # [0, []]
max_with_size([2,3,4]) # [3, [2, 3, 4]]
max_with_size([1,[2,3,4]]) # [3, [2, 3, 4]]
max_with_size([[5,[6],[7,8,9],10,11]]) # [5, [5, [6], [7, 8, 9], 10, 11]]
max_with_size([[1,[2,3,4]],[[[5,[6],[7,8,9],10,11]]]]) # [5, [5, [6], [7, 8, 9], 10, 11]]
So far I've got this
def max_with_size (ary)
max_size = ary.size
max_ary = ary
ary.each { |elem|
if elem.is_a? Array
if elem.size > max_size
max_size = max_with_size(elem)[0]
max_ary = max_with_size(elem)[1]
end
end
}
[max_size, max_ary]
end
It works fine for the first 4 cases, but the 5th fails and only delivers this
max_with_size([[1,[2,3,4]],[[[5,[6],[7,8,9],10,11]]]]) # [2, [[1, [2, 3, 4]], [[[5, [6], [7, 8, 9], 10, 11]]]]]
How can I achieve the wanted result?
The following code should print the desired result. I explained code with Inline comments.
#Initialize #max to empty array, #max is an array with two elements, like this: [max_array_size, max_array]
#max = []
def max_with_size(array)
# when #max is empty or when array size is greater than what is store in #max, store array size and array contents in #max
(#max = [array.size, array]) if #max.empty? || (#max[0] < array.size)
#Iterate through each element in array
array.each do |x|
#Skip to next element if x is not an array
next unless x.is_a? Array
#Recursively find max of array x
max_with_size(x)
end
#max
end
Code
def max_arr(arr)
[arr, *arr.each_with_object([]) {|e,a| a << max_arr(e) if e.is_a?(Array) && e.any?}].
max_by(&:size)
end
Examples
examples = [[],
[2,3,4],
[1,[2,3,4]],
[[5,[6],[7,8,9],10,11]],
[[1,[2,3,4]],[[[5,[6],[7,8,9],10,11]]]],
[1, [2, [3, 4, [6, 7, 8, 9, 10], [11, 12]], 13]]]
examples.each do |arr|
a = max_arr(arr)
puts "\n#{arr}\n \#=> #{a.size}, #{a}"
end·
[]
#=> 0, []
[2, 3, 4]
#=> 3, [2, 3, 4]
[1, [2, 3, 4]]
#=> 3, [2, 3, 4]
[[5, [6], [7, 8, 9], 10, 11]]
#=> 5, [5, [6], [7, 8, 9], 10, 11]
[[1, [2, 3, 4]], [[[5, [6], [7, 8, 9], 10, 11]]]]
#=> 5, [5, [6], [7, 8, 9], 10, 11]
[1, [2, [3, 4, [6, 7, 8, 9, 10], [11, 12]], 13]]
#=> 5, [6, 7, 8, 9, 10]

method that generate numbers unless remaining of quotient is 0 ruby

I want to create a little method that generates 2 random numbers (num1,num2) (let's say from 1 to 100) but these numbers need to be divisable together
put in more mathematics terms, I would like to generate 2 random numbers where the remaining of the quotient is 0
I did this:
def operation
operators = [:/, :+, :-, :*]
#operation = operators.sample
end
def result(num1, num2)
if #operation == :/
unless num1 % num2 != 0
numbers
else
#result = #num1.send(#operation, #num2)
end
else
#result = #num1.send(#operation, #num2)
end
end
def numbers
#num1 = rand(1..100)
#num2 = rand(1..100)
end
numbers
result(#num1,#num2)
the idea is that unless the remaining of the two numbers is 0 it returns the number method again. I believe there is some iteration problem over here, as I receive an error '`result': nil is not a symbol nor a string (TypeError)'
thx
You're not calling the method operation, so #operation will be nil. So it is invalid to use #operation as the method name when you call send.\
I suggest you refactor things so that you aren't storing a bunch of state in instance variables. Instead, pass any data into functions using function arguments.
To ensure that there is no bias in the sampling, you must first construct the universe of all pairs that satisfy the specified conditions. You can do that as follows.
The numbers can range from 1 to a specified maximum, say
mx = 50
For this value of mx the list of valid pairs is constructed as follows.
pairs = (1..mx/2).flat_map { |n| (1..mx/n).map { |m| [n, n*m] } }
#=> [[1, 1], [1, 2],..., [1, 50],
# [2, 2], [2, 4],..., [2, 50],
# [3, 3], [3, 6],..., [3, 48],
# [4, 4], [4, 8],..., [4, 48],
# [5, 5], [5, 10],..., [5, 50],
# [6, 6], [6, 12],..., [6, 48],
# [7, 7], [7, 14],..., [7, 49],
# [8, 8], [8, 16],..., [8, 48],
# [9, 9], [9, 18],..., [9, 45],
# [10, 10], [10, 20],..., [10, 50],
# [11, 11], [11, 22],..., [11, 44],
# [12, 12], [12, 24],..., [12, 48],
# [13, 13], [13, 26], [13, 39],
# [14, 14], [14, 28], [14, 42],
# [15, 15], [15, 30], [15, 45],
# [16, 16], [16, 32], [16, 48],
# [17, 17], [17, 34],
# [18, 18], [18, 36],
# [19, 19], [19, 38],
# [20, 20], [20, 40],
# [21, 21], [21, 42],
# [22, 22], [22, 44],
# [23, 23], [23, 46],
# [24, 24], [24, 48],
# [25, 25], [25, 50]]
pairs_size = pairs.size
#=> 182
Now you can draw random samples of, say, size
sample_size = 10
from this population, either with replacement:
sample_size.times.map { pairs[rand pairs_size] }
#=> [[3, 6], [2, 10], [7, 35], [2, 40], [18, 36],
# [1, 45], [11, 22], [2, 40], [1, 6], [9, 36]]
or without replacement:
pairs.sample(sample_size)
#=> [[22, 22], [6, 42], [1, 28], [1, 42], [1, 20],
# [1, 36], [23, 46], [9, 18], [4, 36], [16, 16]]
If arrays [n, n] (e.g, [2, 2]) are not to be included in pairs, change the block above to
{ |n| (2..mx/n).map { |m| [n, n*m] } }
in which case pairs.size #=> 157.

Splitting an array by performing an arithmetic function in ruby

I have an array in Ruby like [3,4,5] and I want to create sub-arrays by diving or multiplying. For example, I want to multiply each number in the array by 2, 3, and 4, returning [[6,9,12],[8,12,16],[10,15,20]]
After that, what's the best way to count the total number of units? In this example, it would be 9, while array.count would return 3.
Thanks
The simplest way I could think of was:
[3,4,5].map { |v|
[3,4,5].map { |w|
w * v
}
}
I'm sure there is a more elegant way.
As for the count you can use flatten to turn it into a single array containing all the elements.
[[9, 12, 15], [12, 16, 20], [15, 20, 25]].flatten
=> [9, 12, 15, 12, 16, 20, 15, 20, 25]
You might find it convenient to use matrix operations for this, particularly if it is one step among several involving matrices, vectors, and/or scalars.
Code
require 'matrix'
def doit(arr1, arr2)
(Matrix.column_vector(arr2) * Matrix.row_vector(arr1)).to_a
end
def nbr_elements(arr1, arr2) arr1.size * arr2.size end
Examples
arr1 = [3,4,5]
arr2 = [3,4,5]
doit(arr1, arr2)
#=> [[ 9, 12, 15],
# [12, 16, 20],
# [15, 20, 25]]
nbr_elements(arr1, arr2)
#=> 9
doit([1,2,3], [4,5,6,7])
#=> [[4, 8, 12],
# [5, 10, 15],
# [6, 12, 18],
# [7, 14, 21]]
nbr_elements([1,2,3], [4,5,6,7])
#=> 12
Alternative
If you don't want to use matrix operations, you could do it like this:
arr2.map { |e| [e].product(arr1).map { |e,f| e*f } }
Here's an example:
arr1 = [1,2,3]
arr2 = [4,5,6,7]
arr2.map { |e| [e].product(arr1).map { |e,f| e*f } }
#=> [[4, 8, 12],
# [5, 10, 15],
# [6, 12, 18],
# [7, 14, 21]]

Iterate over array of array

I have an array of arrays like the following:
=> [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]
I want to rearrange it by order of elements in the inner array, e.g.:
=> [[1,6,11],[2,7,12],[3,8,13],[4,9,14],[5,10,15]]
How can I achieve this?
I know I can iterate an array of arrays like
array1.each do |bla,blo|
#do anything
end
But the side of inner arrays isn't fixed.
p [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]].transpose
#=> [[1, 6, 11], [2, 7, 12], [3, 8, 13], [4, 9, 14], [5, 10, 15]]
use transpose method on Array
a = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]
a.transpose
#=> [[1, 6, 11], [2, 7, 12], [3, 8, 13], [4, 9, 14], [5, 10, 15]]
Note that this only works if the arrays are of all the same length.
If you want to handle transposing arrays that have different lengths to each other, something like this should do it
class Array
def safe_transpose
max_size = self.map(&:size).max
self.dup.map{|r| r << nil while r.size < max_size; r}.transpose
end
end
and will yield the following
a = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15,16]]
a.safe_transpose
#=> [[1, 6, 11], [2, 7, 12], [3, 8, 13], [4, 9, 14], [5, 10, 15], [nil, nil, 16]]

Resources