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
Array Include Any Value from Another Array
How to Round a Time Down to the Nearest 15 Minutes in Ruby
Determining If a Variable Is Within Range
Connect to a Locally Built Jekyll Server Using Mobile Devices in the Lan
Rails: Encoding Woes with Serialized Hashes Despite Utf8
Net::Ssh Sudo Command Hangs After Entering Password
Sort a Collection of Objects by Number (Highest First) Then by Letter (Alphabetical)
How to Read Whole File in Ruby
Regex, How to Match Multiple Lines
Why Does My Rails Rollback When I Try to User.Save
Switch Theme in an Existing Jekyll Installation
Keep Getting Oauth::Unauthorized Error When Using Oauth and Twitter Ruby Gems
Ruby and Linux, Preferred Setup