I need to tell if an array contains all of the elements of another array with duplicates.
[1,2,3].contains_all? [1,2] #=> true
[1,2,3].contains_all? [1,2,2] #=> false (this is where (a1-a2).empty? fails)
[2,1,2,3].contains_all? [1,2,2] #=> true
So the first array must contain as many or equal of the number of each unique element in the second array.
This question answers it for those using an array as a set, but I need to control for duplicates.
On Ruby 1.9.3p194
def bench
puts Benchmark.measure {
10000.times do
[1,2,3].contains_all? [1,2]
[1,2,3].contains_all? [1,2,2]
[2,1,2,3].contains_all? [1,2,2]
end
}
end
Results in:
Rohit 0.100000 0.000000 0.100000 ( 0.104486)
Chris 0.040000 0.000000 0.040000 ( 0.040178)
Sergio 0.160000 0.020000 0.180000 ( 0.173940)
sawa 0.030000 0.000000 0.030000 ( 0.032393)
@a1 = (1..10000).to_a
@a2 = (1..1000).to_a
@a3 = (1..2000).to_a
def bench
puts Benchmark.measure {
1000.times do
@a1.contains_all? @a2
@a1.contains_all? @a3
@a3.contains_all? @a2
end
}
end
Results in:
Rohit 9.750000 0.410000 10.160000 ( 10.158182)
Chris 10.250000 0.180000 10.430000 ( 10.433797)
Sergio 14.570000 0.070000 14.640000 ( 14.637870)
sawa 3.460000 0.020000 3.480000 ( 3.475513)
1) Check if an array contains a string If you want to ingore the letter cases when checking, you can: First, return a new array that contains all elements in lowercase using the map() and toLocaleLowerCase() methods. Then, use the includes() method to check.
Try sorting both arrays and iterating over both of them at the same, first squaring the number from the first array and then checking if it is equal to the element from the second array. Once you reach non-equal elements return false, otherwise return true.
Use the . filter() method on the first array and check if the elements of first array are not present in the second array, Include those elements in the output.
class Array
def contains_all? other
other = other.dup
each{|e| if i = other.index(e) then other.delete_at(i) end}
other.empty?
end
end
Here's a naive and straightforward implementation (not the most efficient one, likely). Just count the elements and compare both elements and their occurrence counts.
class Array
def contains_all? ary
# group the arrays, so that
# [2, 1, 1, 3] becomes {1 => 2, 2 => 1, 3 => 1}
my_groups = group_and_count self
their_groups = group_and_count ary
their_groups.each do |el, cnt|
if !my_groups[el] || my_groups[el] < cnt
return false
end
end
true
end
private
def group_and_count ary
ary.reduce({}) do |memo, el|
memo[el] ||= 0
memo[el] += 1
memo
end
end
end
[1, 2, 3].contains_all? [1, 2] # => true
[1, 2, 3].contains_all? [1, 2, 2] # => false
[2, 1, 2, 3].contains_all? [1, 2, 2] # => true
[1, 2, 3].contains_all? [] # => true
[].contains_all? [1, 2] # => false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With