Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

comparing sequences in Ruby

Assuming I have to (small-to-medium) arrays:

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

How can I determine whether tokens contains all entries of template, in that same order?

(Note that in the example above, the first "ccc" should be ignored, resulting in a match due to the last "ccc".)

like image 375
anon Avatar asked Aug 09 '11 09:08

anon


3 Answers

This works for your sample data.

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

pos = 0
condition_met = true
template.each do |temp|
  if (tpos = tokens[pos..-1].index temp) == nil then
    break condition_met = false
  else
    pos = tpos
  end
end

puts condition_met
like image 164
manatwork Avatar answered Sep 30 '22 09:09

manatwork


Cleanest, I think, to do this via recursion:

class Array
  def align(other)
    if pos = index(other.first)
      other.size == 1 || slice(pos..-1).align(other.drop(1))
    end
  end
end

so:

[1,2,3,4,3,2,1].align([1,2,3])
=> true
[1,2,3,4,3,2,1].align([1,4,1])
=> true
[1,2,3,4,3,2,1].align([1,4,2,3])
=> nil
like image 38
glenn mcdonald Avatar answered Sep 30 '22 08:09

glenn mcdonald


Solution provided by manatwork is good, but here is one that seems more ruby-ish to me:

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

def tokens_include_template(tokens, template)
  tokens = tokens.to_enum
  template.each do |t|
    return false unless loop { break true if t == tokens.next }
  end
  true
end

puts tokens_include_template(tokens, template)
like image 29
Victor Deryagin Avatar answered Sep 30 '22 08:09

Victor Deryagin