Check If an Array Is Subset of Another Array in Ruby

Check if an array is subset of another array in Ruby

Use sets. Then you can use set.subset?. Example:

require 'set'

a1 = Set[3,6,4]
a2 = Set[1,2,3,4,5,6,7,8,9]

puts a1.subset?(a2)

Output:

true

See it working online: ideone

How to find if one array is a subset of another array in Ruby?


[b, c, d].map do |arr|
a.each_cons(arr.length).any?(&arr.method(:==))
end
#⇒ [true, false, false]

This is definitely not the most performant solution, but for not huge arrays is works and, which is important, is readable.

Enumerable#each_cons.

How to determine if one array contains all elements of another array


a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

a - b
# => [5, 1, 14, 8]

b - a
# => [15]

(b - a).empty?
# => false

Check if array is an ordered subset


b == a & b

That checks whether b is contained in a in the same order.

In other words: In general you have B⊆A ⇔ B=A∩B. And Ruby's Array#& preserves the order (of the left operand).

Ruby: Array contained in Array, any order


def f a,b
(a-b).empty?
end

Check if each element of an array is included in a set of values of another array

The easiest thing would be to do a set intersection and see what you get from that:

intersection = array1 & array2
if intersection.length == array1.length
# Everything in array1 is in array2
end

That would, of course, fail if array1 had duplicates as the intersection will automatically compress those. But we have uniq to take care of that:

intersection = array1 & array2
if intersection.length == array1.uniq.length
# Everything in array1 is in array2
end

If you're expecting duplicates in your arrays then you'd be better off working with instances of Set rather than arrays:

require 'set'
s1 = Set.new(array1)
s2 = Set.new(array2)

if((s1 & s2) == s1)
# Everything in array1 is in array2
end

Or use subset? to better match your intentions:

if(s1.subset?(s2))
# Everything in array1 is in array2
end

Using sets will take care of your duplicate issues with less noise than having to use uniq all the time. There would, of course, be a bit of extra overhead but you should optimize for clarity before performance (make it work then make it fast only if it is too slow).

(Ruby) How do you check whether a range contains a subset of another range?

Be careful using this with large ranges but this is an elegant way to do it:

(x.to_a & y.to_a).empty?

dissecting this code, explanation - check if array subset of another array

2nd line:

    ${@/%/[key]}

% as first character of the pattern indicates that pattern has to match at the end. There is nothing else in the pattern so the meaning is "replace empty string at the end, with '[key]'". After that positional parameters look like this:

    1 = a[key]
2 = b[key]

Next line:

but shouldn't it be reverse, returning 1 if first array has more elements,

But it does that. Notice that || operator is used, so it will return 1 if the condition is not met. The condition is: "x.size <= y.size", so it will return 1 if "x.size > y.size".

Finally:

    [[ ${!2+_} && ${!1} == ${!2} ]] || return 1

To be honest, I don't know what +_ is for. As for the rest, notice that we are in a loop with a key variable. We also have key in our positional variables, so:

    ${!1}

becomes

    ${a[key])

and key variable takes values of keys from array a. So the whole test verifies that value with given key exists in the second array:

    [[ ${!2+_} && ...

and that value with that key in the first array is the same as the value with that key in the second array:

    ... && ${!1} == ${!2} ]]

The first condition is necessary to detect the case when you pass array a which at index i has empty string and array b which doesn't have index i:

local -a 'a=([1]="" 2 3)' 'b=([2]=2 {3..10})'
isSubset a b
echo $? # false

Ruby - Show Deltas Between 2 array of hashes based on subset of hash keys

This isn't very pretty, but it works. It creates a third array containing all unique values in both array1 and array2 and iterates through that.

Then, since include? doesn't allow a custom matcher, we can fake it by using detect and looking for an item in the array which has the custom sub-hash matching. We'll wrap that in a custom method so we can just call it passing in array1 or array2 instead of writing it twice.

Finally, we loop through our array3 and determine whether the item came from array1, array2, or both of them and add to the corresponding output array.

array1 = [{'id' => '1', 'ref' => '1001', 'name' => 'CA', 'extra' => 'Not Sorted On 5'},
{'id' => '2', 'ref' => '1002', 'name' => 'NY', 'extra' => 'Not Sorted On 7'},
{'id' => '3', 'ref' => '1003', 'name' => 'WA', 'extra' => 'Not Sorted On 9'},
{'id' => '7', 'ref' => '1007', 'name' => 'OR', 'extra' => 'Not Sorted On 11'}]

array2 = [{'id' => '1', 'ref' => '1001', 'name' => 'CA', 'extra' => 'Not Sorted On 5'},
{'id' => '3', 'ref' => '1003', 'name' => 'WA', 'extra' => 'Not Sorted On 9'},
{'id' => '8', 'ref' => '1002', 'name' => 'NY', 'extra' => 'Not Sorted On 7'},
{'id' => '5', 'ref' => '1005', 'name' => 'MT', 'extra' => 'Not Sorted On 10'},
{'id' => '12', 'ref' => '1012', 'name' => 'TX', 'extra' => 'Not Sorted On 85'}]

# combine the arrays into 1 array that contains items in both array1 and array2 to loop through
array3 = (array1 + array2).uniq { |item| { 'id' => item['id'], 'ref' => item['ref'], 'name' => item['name'] } }

# Array#include? doesn't allow a custom matcher, so we can fake it by using Array#detect
def is_included_in(array, object)
object_identifier = { 'id' => object['id'], 'ref' => object['ref'], 'name' => object['name'] }

array.detect do |item|
{ 'id' => item['id'], 'ref' => item['ref'], 'name' => item['name'] } == object_identifier
end
end

# output array initializing
array1_only = []
array2_only = []
array1_and_array2 = []

# loop through all items in both array1 and array2 and check if it was in array1 or array2
# if it was in both, add to array1_and_array2, otherwise, add it to the output array that
# corresponds to the input array
array3.each do |item|
in_array1 = is_included_in(array1, item)
in_array2 = is_included_in(array2, item)

if in_array1 && in_array2
array1_and_array2.push item
elsif in_array1
array1_only.push item
else
array2_only.push item
end
end


puts array1_only.inspect # => [{"id"=>"2", "ref"=>"1002", "name"=>"NY", "extra"=>"Not Sorted On 7"}, {"id"=>"7", "ref"=>"1007", "name"=>"OR", "extra"=>"Not Sorted On 11"}]
puts array2_only.inspect # => [{"id"=>"8", "ref"=>"1002", "name"=>"NY", "extra"=>"Not Sorted On 7"}, {"id"=>"5", "ref"=>"1005", "name"=>"MT", "extra"=>"Not Sorted On 10"}, {"id"=>"12", "ref"=>"1012", "name"=>"TX", "extra"=>"Not Sorted On 85"}]
puts array1_and_array2.inspect # => [{"id"=>"1", "ref"=>"1001", "name"=>"CA", "extra"=>"Not Sorted On 5"}, {"id"=>"3", "ref"=>"1003", "name"=>"WA", "extra"=>"Not Sorted On 9"}]


Related Topics



Leave a reply



Submit