Given I have an array of 3 strings:
["Extra tv in bedroom",
"Extra tv in living room",
"Extra tv outside the shop"]
How do I find the longest string all strings have in common?
Given I have an array of 3 strings:
["Extra tv in bedroom",
"Extra tv in living room",
"Extra tv outside the shop"]
How do I find the longest string all strings have in common?
This wikipedia article explains two algorithms that can be used to solve that problem.
If you want to search for the beginning of all strings:
def substr( a )
return "" unless (a.length > 0)
result = 0
(0 ... a.first.length).each do |k|
all_matched = true
character = a.first[k]
a.each{ |str| all_matched &= (character == str[k]) }
break unless all_matched
result+=1
end
a.first.slice(0,result)
end
input = ["Extra tv in bedroom",
"Extra tv in living room",
"Extra tv outside the shop"]
puts substr( input ) + "."
Extra tv .
Here's a rubyish way of doing it. You should use a more advanced algorithm if you have a bunch of strings or they are very long, though:
def longest_common_substr(strings)
shortest = strings.min_by &:length
maxlen = shortest.length
maxlen.downto(1) do |len|
0.upto(maxlen - len) do |start|
substr = shortest[start,len]
return substr if strings.all?{|str| str.include? substr }
end
end
end
puts longest_common_substr(["Extra tv in bedroom",
"Extra tv in living room",
"Extra tv outside the shop"])
Don't think this scales particularly well.
def longest_substr(text)
if (text.length == 0)
return ""
elseIf (text.length == 1)
return text[0]
end
longest = text.inject(text[0].length) {|min, s| min < s.length ? min : s.length}
(1 .. longest).to_a.reverse.each do |l|
(0 .. text[0].length - l).each do |offset|
str = text[0].slice(offset, l)
matched = (1 .. text.length - 1).inject(true) {|matched, i| matched && text[i].index(str) != nil}
if (matched)
return str
end
end
end
return ""
end
puts longest_substr(["Alice's Extra tv in bedroom",
"Bob's Extra tv in living room",
"My Extra tv outside the shop"])
Also only for the beginning of strings.
def longest_subsequence array
array.sort!
first = array[0].split(//)
last = array[-1].split(//)
length = (first.size > last.size) ? last.size : first.size
sequence = ""
index = 0
while (first[index] == last[index]) && (index < length)
sequence << first[index]
index += 1
end
sequence
end
But I think there ought to be a way to easily compare the beginning of just two strings for a matching substring - I just can't think of it right now!
Don't know if a response is still useful, but here's a solution inspired by @mckeed and @lins314159 code.
def longest_common_substr(strings)
longest_substring = strings.map{|s| s.split}.max_by &:length
longest_substring.inject do |target_str, token|
r = Regexp.new("^#{target_str.nil? ? token : "#{target_str} #{token}".strip}")
target_str = "#{target_str} #{token}".strip if strings.all? {|string| string =~ r}
target_str
end
end
puts longest_common_substr(["Extra tv and mat in bedroom",
"Extra tv and chair with view in living room",
"Extra tv and carpet outside the shop"])