2

Is it possible to check inclusion array inside array?

i want to check if

primary = [1,2,3] includes secondary = [2,3]

i have tried primary.include?(secondary) => false

need to return bool value

12
  • 2
    not clear what you are asking Commented Jan 5, 2017 at 10:44
  • 3
    Are you searching for something similar to a subset or something similar to a substring? Commented Jan 5, 2017 at 10:45
  • 3
    this question has been asked several times stackoverflow.com/questions/5890717/… stackoverflow.com/questions/7387937/… Commented Jan 5, 2017 at 10:47
  • 1
    Do you want to check if elements 2,3 are present in primary or if [2,3] array is present inside primary array? The one which you have shown checks if array [2,3] is present inside primary array and as it is not present it returns false. Commented Jan 5, 2017 at 10:47
  • 2
    Could the arrays contain duplicates values? For example primary = [1, 1, 2] and secondary = [1, 2, 2]. If so, how would you define "inclusion" in that case? Commented Jan 5, 2017 at 10:59

8 Answers 8

4

Solution

Without duplicates

If there aren't any duplicate, you can calculate the Array difference, and check if it is empty :

(secondary-primary).empty?
#=> true

General case

subset_of? checks that for every unique element in secondary, there are at least as many elements in primary :

class Array
  def count_by
    each_with_object(Hash.new(0)) { |e, h| h[e] += 1 }
  end

  def subset_of?(superset)
    superset_counts = superset.count_by
    count_by.all? { |k, count| superset_counts[k] >= count }
  end
end

Example :

secondary.subset_of?(primary)
#=> true
[2,2].subset_of?([1, 2, 3])
#=> false

This should work for any Array, and it should be faster than other answers for big arrays.

Test

([1,2,3] - [3,4,5,2,1]).empty?
#=> true
([1,2,3,'a'] - [3,4,5,2,1]).empty?
#=> false
Sign up to request clarification or add additional context in comments.

3 Comments

It won’t work for duplicated entries: [2, 2][1, 2], while your solution gives true.
Shoot, you're right. Thanks.
The latter is a good one.
3
test = primary.dup
secondary.all? { |e| test.index(e).tap { |i| test.delete_at(i) if i } }

primary, secondary = [1, 2, 3], [2, 2]
#⇒ false

primary, secondary = [1, 2, 2, 3], [2, 2, 1]
#⇒ true

What’s being done here:

  • we iterate secondary, claiming that all blocks should return true
  • on each subsequent iteration we
    • immediately return false breaking the loop if there is no such element in primary
    • otherwise we mutate the copy of primary, removing the element already checked.

The only trick here is using Object#tap to always return true when element found. The element in the primary might be falsey, Array#delete returns the element deleted and we might accidentally return falsey, mistakenly breaking a loop in such a case. We should return true to all? loop as soon as we have the element found, hence tap.

The input to verify that this is the only correct answer here so far:

primary, secondary = [1, 2, 2, 3, nil, nil], [2, 2, 1, nil, nil]
#⇒ true

primary, secondary = [1, 2, 2, 3, nil], [2, 2, 1, nil, nil]
#⇒ false

4 Comments

@Stefan good point, fixed.
@mudasobwa Can you please add little detail, like what tap will do here? And before this you assigned the index to i now you have created a block which will do similar thing. I am trying to understand the answer, but right now it is not clear to me.
@Deep please see an update.
This works for any arrays, but it can become very slow for large arrays. primary = (1..100_000).to_a and secondary = primary.reverse for example.
1
primary = [1,2,3]
secondary = [2,3]
primary.each_cons(secondary.size).include?(secondary)

Enumerable#each_cons takes chunks of the array and iterates by one for each group.
Enumerable is awesome!

Read the Enumerable docs, I learn something new every time.

2 Comments

This only works for consecutive elements. It won't work for secondary = [1, 3]
@Stefan I don't think that is what OP is asking. It sounds like they want the inclusion of the whole secondary array in the original. But you'd be right if that isn't what the OP is asking.
0
a = [5, 1, 6, 14, 2, 8]
b = [2, 6, 15]

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

b - a
=> [15]

#this is what you need
(b - a).empty?
=> false

Comments

0

Here solution

primary=[1,2,3]  
secondary=[2,3]  
secondary.all? { |e| primary.include?(e) }

1 Comment

This is simply wrong. Try for secondary = [2, 2].
0

To check if an array is present inside another array, just use the include? method,

primary = [1,2,3,[1,2]]
secondary = [2,3]

result = primary.include? secondary
# returns false as [2,3] is not present

primary = [1,2,3,[1,2]]
secondary = [1,2]
result = primary.include? secondary
# returns true as [1,2] is present

To check if the elements of secondary array are present inside the primary array, takes care of the duplicate elements also:

result = (secondary.select {|i| secondary.count(i)<=primary.count(i)}.length == secondary.length)

primary, secondary = [1, 2, 3], [2, 2]
# returns false

primary, secondary = [1, 2, 2, 3], [2, 2, 1]
# returns true

1 Comment

Now the answer is sorta correct, but I am afraid to think how many iterations it requires on huge arrays.
0

a1 = [5, 3, 9, 7, 8, 7, 1, 7]

a2 = [1, 9, 5, 7, 5]

It will check elements of a2 are present in a1 or not,

a2.all?{ |i| a1.include? i } #=> true

1 Comment

It returns true, although a1 only contains one 5.
-1

Using

secondary.all? { |e| primary.include?(e) }

Use Intersection

(primary & secondary).size == secondary.uniq.size

If any element of secondary to be present in primary

(primary & secondary).present?

Hope it helps

8 Comments

Sorry, but this is wrong : ([1,7] & [2,7]).present? #=> true
I thought any one element from secondary to be present in primary.
I think inclusion refers to subset : en.wikipedia.org/wiki/Subset. I didn't downvote BTW.
DownVoter can you please remove it.
@GouravNaik I have it downvoted and I did it because this answer is wrong. Try [1, 2, 2] & [2, 2].
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.