1

Preferably in Ruby

I need a way to determine if one array is a "subarray" of another array when order matters

For instance,

a = ["1", "4", "5", "7", "10"]
b = ["1", "4", "5"]
c = ["1", "5", "4"]
d = ["1", "5", "10"]

a includes b = true
a includes c = false
a include d = false

Thanks in advance.

11
  • @ruakh is this a duplicate if the user wants answer in Ruby? Commented Apr 28, 2018 at 7:19
  • @ruakh based on the examples in the test cases given, this is NOT a duplicate I don't think. See stackoverflow.com/questions/26568560/… Commented Apr 28, 2018 at 8:40
  • 1
    I don't think this is a duplicate, because elements must be consecutive. Commented Apr 28, 2018 at 9:23
  • 2
    I have it reopened. Commented Apr 28, 2018 at 9:24
  • 1
    @mudasobwa Good one. Commented Apr 28, 2018 at 9:25

4 Answers 4

4
[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.

Sign up to request clarification or add additional context in comments.

1 Comment

Could we use a.each_cons(arr.length).include?(arr) to achieve same effect?
0
a = ["1", "4", "5", "7", "10"]
b = ["1", "4", "5"]
c = ["1", "5", "4"]
d = ["1", "5", "10"]


def sub_set?(arr_a, arr_b)
  arr_a.select.with_index do |a, index|
    arr_b[index] == a
  end == arr_b
end

puts "testing sub_set #{a.inspect} and #{c.inspect}"
puts sub_set?(a,c).inspect

3 Comments

You might use detect.with_index { |a, i| arr_b[i] != a } instead of select to fail fast.
Now it does not work at all, it should be detect {...} ? false : true.
@mudasobwa I've spent too much time on getting you guys to first reopen this issue, and now I'm tired. You're answer is better. I'm going to bed. thanks.
0
class Array
  def includes(array)
    return false if array.size > self.size
    indexes = []
    self.each_with_index {|e, i| indexes << i if e == array[0]}
    p indexes
    indexes.each do |i|
      return true if self[i..i+array.size-1] == array
    end
    return false
  end
end

p a.includes b
p a.includes c
p a.includes d

Or less phpish :)

class Array
  def includes(array)
    return false if array.size > self.size
    indexes = each.with_index.select { |e, i| e == array[0] }.map(&:last)
    indexes.each {|i| self[i..i+array.size-1] == array ? (return true) : (return false)}
  end
end

p a.includes b
p a.includes c
p a.includes d

3 Comments

indexes = select.with_index { |e, i| e == array[0] }.map(&:last) would be less phpish.
Ah, sorry, my bad, it should be indexes = each.with_index.select { |e, i| e == array[0] }.map(&:last), because if select goes before with_index, it selects plain elements.
Are you really posting a monkey patch and with 2 versions just with different method names? And 4 space indentations?
0

You could join the elements with an arbitrary character then compare strings:

a.join(' ').match?(array.join(' '))

This works for the test cases you have provided:

a.join(' ').match?(b.join(' '))                                                                                                                     
 #=> true
a.join(' ').match?(c.join(' '))                                                                                                                     
 #=> false
a.join(' ').match?(d.join(' '))                                                                                                                   
 #=> false

But this is not a general solution and will fail on varying types of arrays (see comments for further discussion).

11 Comments

This fails if array contains non-strings. The method should work for any array values.
@lacostenycoder Okay, this is probably not a robust or work-for-all approach, but it can be used in many cases (an array of strings or an array of integers for example). Which may suffice for the OP's needs, so it's worth mentioning as an answer.
@SagarPandya. I was gonna do it this way but thought I'd get slammed or down voted so I tried to find something which didn't rely on string conversion. This way is the easy way. I'm suffering from insomnia so sorry for the down vote. But also see stackoverflow.com/questions/33174985/… because this was tagged as duplicate when I started. Make some edit and I'll reverse it.
@lacostenycoder Yes I was just looking for a cheeky shortcut, but I should have mentioned its shortcomings in my answer. Your downvote is fine, you have a valid reason. I only dislike downvotes when no or an invalid reason is given.
Had there been no downvotes I probably wouldn't have upvoted, but I don't think downvotes are deserved, so I've upvoted to offset up to five of them. I don't believe the lack of robustness is a fair objection as the OP's example suggests that all the array elements are strings (of digits).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.