8

In ruby, how do I test that one array not only has the elements of another array, but contain them in that particular order?

correct_combination = [1, 2, 3, 4, 5]
[1, 5, 8, 2, 3, 4, 5].function_name(correct_combination) # => false
[8, 10, 1, 2, 3, 4, 5, 9].function_name(correct_combination) # => true

I tried using include, but that is used to test whether [1,2,3].include?(2) is true or not.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
  • Similar question at http://stackoverflow.com/questions/6993848/comparing-sequences-in-ruby – Andrew Grimm Aug 10 '11 at 00:10
  • @jassa I tried using it (without `should`, which is a rspec thing), and both `[8, 10, 1, 2, 3, 4, 5, 9] =~ correct_combination` and `correct_combination =~ [8, 10, 1, 2, 3, 4, 5, 9]` returned `nil` for ruby 2.0.0dev (2011-11-27 trunk 33860). – Andrew Grimm Apr 13 '12 at 23:20
  • You are right, let me elaborate – jassa Apr 14 '12 at 04:16

11 Answers11

15

You can use each_cons method:

arr = [1, 2, 3, 4, 5]
[1, 5, 8, 2, 3, 4, 5].each_cons(arr.size).include? arr

In this case it will work for any elements.

Yossi
  • 11,778
  • 2
  • 53
  • 66
10

I think it can be done simply.

class Array
  def contain? other; (self & other) == other end
end

correct_combination = [1, 2, 3, 4, 5]
[1, 5, 8, 2, 3, 4, 5].contain?(correct_combination) # => false
[8, 10, 1, 2, 3, 4, 5, 9].contain?(correct_combination) # => true
sawa
  • 165,429
  • 45
  • 277
  • 381
  • 2
    I don't think this is accurate for checking that the numbers appear in the given order. For example, if `correct_combination = [1,3,4]` then `[1, 5, 8, 2, 3, 4, 5].contain?(correct_combination)` returns true. – davemyron Oct 10 '13 at 19:58
  • That is the expected result. You may have not understood the question. – sawa Oct 10 '13 at 20:04
4

If you want to ignore the order, (as I did when I came across this post), you could use Array.sort and <=> http://ruby-doc.org/core-1.8.7/classes/Array.html#M000316

a = [1, 2, 3, 4, 5]
b = [2, 1, 5, 4, 3]
a.sort <=> b.sort

You then need to check the output value equals 0.

Jamie Cobbett
  • 339
  • 2
  • 4
  • Would this work if one array had more contents than the other? – Andrew Grimm Jun 06 '10 at 01:01
  • No, because <=> is testing for equality, and we have made it so that if the same values are in each array, they will be equal once both sorted. As the linked documentation says: Thus, two arrays are ``equal’’ according to Array#<=> if and only if they have the same length and the value of each element is equal to the value of the corresponding element in the other array. – Jamie Cobbett Jun 06 '10 at 22:25
3

Not exactly the best solution possible, but at least it's brief

(',' + [1, 5, 8, 2, 3, 4, 5].join(',') + ',').include?(',' + correct_combination.join(',') + ',')

The best solution possible would be to employ one of string searching algorithms on array but you would have to code it yourself, I don't think there's standard solution.

vava
  • 24,851
  • 11
  • 64
  • 79
0

This is what I came up with

a = [1, 2, 3, 4, 5]
b = [2, 3, 5]
c = [3, 9]

irb(main):037:0* (a + b).sort.uniq == a.sort.uniq
=> true
irb(main):038:0> (a + c).sort.uniq == a.sort.uniq
=> false
Tallak Tveide
  • 351
  • 1
  • 4
0

I would like to consider continuous sequence of elements from other array in container array and present this:-- code is inspired from the Sawa's code

class Array
  def contain? other
   arr = self & other
   (arr.eql? other ) && ((self.index(arr.last) - self.index(arr.first)).eql?(other.size - 1))
  end
end

Result:--

correct_combination = [1, 2, 3, 4, 5]
[1, 5, 8, 2, 3, 4, 5].contain?(correct_combination) # => false
[8, 10, 1, 2, 3, 4, 5, 9].contain?(correct_combination) # => true
[1, 8, 2, 3, 4, 5].contain?(correct_combination) # => false
Alok Anand
  • 3,346
  • 1
  • 20
  • 17
  • @orangechicken Are you looking for this? – Alok Anand Mar 18 '14 at 16:05
  • @AndrewGrimm logic is 1. intersection of container and combination array should be equal to combination, 2. subtraction of index of first element of combination in container from index of last element of combination in container must be equal to size of combination minus one. See examples in answer. – Alok Anand Mar 19 '14 at 02:31
-1

I would suggestion a for loop that compares each one

@out_of_order_elements = []

for i in 0.. @array_size do
  unless submission_array[i] == @correct_combination[i]
    @out_of_order_ids.push(@submission_array[i])
  end
end 
ajbraus
  • 2,909
  • 3
  • 31
  • 45
-2

Maybe <=> is what you are looking for.

Comparison—Returns an integer (-1, 0, or +1) if this array is less than, equal to, or greater than other_array

a = [1, 2, 3, 4, 5]
b = [1, 5, 8, 2, 3, 4, 5]
c = [8, 10, 1, 2, 3, 4, 5, 9]

puts a <=> b # => -1
puts a <=> c # => -1
puts a <=> a # => 0

Update: nevermind, just noted it doesn't care about position.

puts a <=> a.reverse # => -1
gaqzi
  • 3,707
  • 3
  • 30
  • 30
-2

This is the best I could come up with. All the return calls are a bit ugly, but it should be quicker than doing a string comparison if it's large arrays.

class Array
  def same?(o)
    if self.size == o.size
      (0..self.size).each {|i| return false if self[i] != o[i] }
    else
      return false
    end

    return true
  end
end

a = [1,2,3,4,5]
b = [1, 5, 8, 2, 3, 4, 5]
c = [1, 2, 6, 4, 5]

puts a.same?(a.reverse) # => false
puts a.same?(a) # => true
puts a.same?(b) # => false
puts a.same?(c) # => false
gaqzi
  • 3,707
  • 3
  • 30
  • 30
  • I see now that I misunderstood the question completely. Yossi Zach seem to be on to the correct answer with `each_cons`. :) – gaqzi May 18 '10 at 08:55
  • you dont need to explicitly write `return true` in Ruby you can just write `true` – Agush Sep 12 '13 at 09:19
-2

A really quick way to do this is to simply subtract one array from the other and test for an empty array.

correct_combination = [1, 2, 3, 4, 5]
yep = [8, 10, 1, 2, 3, 4, 5, 9]
nope = [1, 8, 2, 3, 4]
if correct_combination - yep == []
  puts "yep has all the values"
end
if correct_combination - nope == []
  puts "nope has all the values"
end

This approach does not care about position so delete away!

Sorry... I missed the point to the question as well. Didn't realize you were looking for order of precedence. I came across this when looking for a solution to evaluating if one large array contained all the entries of another large array. The .all?/include? approach takes a really long time to complete. Good luck!

BenH
  • 26
  • 3
-3

You could simply compare the arrays as strings:

correct_combination = [1, 2, 3, 4, 5]
yep = [8, 10, 1, 2, 3, 4, 5, 9]
nope = [1, 5, 8, 2, 3, 4, 5]
if yep.to_s.include?(correct_combination.to_s)
  puts "yep"
end
if nope.to_s.include?(correct_combination.to_s)
  puts "nope"
end
Dave Everitt
  • 17,193
  • 6
  • 67
  • 97
  • 1
    http://stackoverflow.com/questions/1553462/check-if-a-string-contains-a-certain-number/1553489#1553489 is all over again :) – vava May 18 '10 at 07:54
  • `yep.to_s.include?(correct_combination.to_s)` returns false, because of the closing bracket of `correct_combination`. – Andrew Grimm May 18 '10 at 23:20