检查一个字符串的字母在另一个字符串中是不是按顺序排列
Posted
技术标签:
【中文标题】检查一个字符串的字母在另一个字符串中是不是按顺序排列【英文标题】:check if letters of a string are in sequential order in another string检查一个字符串的字母在另一个字符串中是否按顺序排列 【发布时间】:2019-04-17 08:11:05 【问题描述】:如果只是检查 test_string 中的字母是否也在 control_string 中,
我不会有这个问题。
我将简单地使用下面的代码。
if set(test_string.lower()) <= set(control_string.lower()):
return True
但我也面临着一个相当复杂的任务,即辨别
中的重叠字母是否control_string 与 test_string 的顺序相同。
例如,
test_string = 'Dih'
control_string = 'Danish'
True
test_string = 'Tbl'
control_string = 'Bottle'
False
我曾想过使用 for 迭代器来比较字母表的索引,但很难想出合适的算法。
for i in test_string.lower():
for j in control_string.lower():
if i==j:
index_factor = control_string.index(j)
我的计划是将主索引因子与下一个因子进行比较,如果主索引因子大于另一个,则函数返回 False。
我被困在如何在 for 循环中比较那些 index_factors。
我应该如何解决这个问题?
【问题讨论】:
【参考方案1】:这是一种解决方案。这个想法是遍历 control
字符串 first 并在它匹配下一个 test
字符时产生一个值。如果匹配的总数等于test
的长度,那么你的条件就满足了。
def yield_in_order(x, y):
iterstr = iter(x)
current = next(iterstr)
for i in y:
if i == current:
yield i
current = next(iterstr)
def checker(test, control):
x = test.lower()
return sum(1 for _ in zip(x, yield_in_order(x, control.lower()))) == len(x)
test1, control1 = 'Tbl', 'Bottle'
test2, control2 = 'Dih', 'Danish'
print(checker(test1, control1)) # False
print(checker(test2, control2)) # True
@tobias_k's answer 有更简洁的版本。如果您想要一些其他信息,例如多少多少个字母在找到中断之前对齐,您可以简单地调整checker
函数以返回sum(1 for _ in zip(x, yield_in_order(...)))
。
【讨论】:
这实际上接近我的第二个解决方案(没有看到它),但似乎过于复杂。为什么yield i
和j
比较?你已经知道他们是平等的。你不能只检查产生的元素数量吗?
@tobias_k,好点。我确实尝试了sum(1 for _ in yield_in_order(x, control.lower())) == len(x)
,但我得到了DeprecationWarning: generator 'yield_in_order' raised StopIteration
[我不明白],即使结果是正确的。
我猜想在iterstr
用尽之后尝试匹配更多字符时就是这种情况。使用x
压缩会限制生成器请求的项目数。所以zip
他们是有道理的,但==
仍然是多余的。
@tobias_k,是的,花了一点时间但想通了.. 可以sum(1 for ...)
。不过,您的解决方案更清晰。【参考方案2】:
您可以只将join
字符串中的test
字符转换为regular expression,允许介于两者之间的任何其他字符.*
,然后re.search
在control
字符串中使用该模式。
>>> test, control = "Dih", "Danish"
>>> re.search('.*'.join(test), control) is not None
True
>>> test, control = "Tbl", "Bottle"
>>> re.search('.*'.join(test), control) is not None
False
不使用正则表达式,您可以从control
字符串创建一个iter
,并使用两个嵌套循环,1)break
来自内部循环,else
返回@ 987654333@ 直到test
中的所有字符都在control
中找到。即使control
已经是可迭代的,创建iter
也很重要,这样内部循环将在上次停止的地方继续。
def check(test, control):
it = iter(control)
for a in test:
for b in it:
if a == b:
break
else:
return False
return True
您甚至可以使用all
和any
在一行(嗯,两行)中完成此操作:
def check(test, control):
it = iter(control)
return all(any(a == b for b in it) for a in test)
这两种方法的复杂度都应该是 O(n),其中 n 是最大字符数。
1) 这在概念上类似于 @jpp 所做的,但恕我直言更清楚一点。
【讨论】:
【参考方案3】:一种简单的方法是使用sorted
中的key
参数,它用作排序比较的键:
def seq_order(l1, l2):
intersection = ''.join(sorted(set(l1) & set(l2), key = l2.index))
return True if intersection == l1 else False
因此,这是计算两个集合的交集并根据较长的字符串对其进行排序。完成后,您只需将结果与较短的字符串进行比较,看看它们是否相同。
函数相应地返回 True 或 False。使用您的示例:
seq_order('Dih', 'Danish')
#True
seq_order('Tbl', 'Bottle')
#False
seq_order('alp','apple')
#False
【讨论】:
【参考方案4】:您可以使用find(letter, last_index)
来查找处理过的字母后出现的所需字母。
def same_order_in(test, control):
index = 0
control = control.lower()
for i in test.lower():
index = control.find(i, index)
if index == -1:
return False
# index += 1 # uncomment to check multiple occurrences of same letter in test string
return True
如果测试字符串有重复的字母,例如:
test_string = 'Diih'
control_string = 'Danish'
带注释行same_order_in(test_string, control_string) == True
并且带有未注释的行same_order_in(test_string, control_string) == False
【讨论】:
【参考方案5】:使用生成器的优雅解决方案:
def foo(test_string, control_string):
if all(c in control_string for c in test_string):
gen = (char for char in control_string if char in test_string)
if all(x == test_string[i] for i, x in enumerate(gen)):
return True
return False
print(foo('Dzn','Dahis')) # False
print(foo('Dsi','Dahis')) # False
print(foo('Dis','Dahis')) # True
首先检查test_string
中的所有字母是否都包含在control_string
中。然后检查该订单是否与test_string
订单相似。
【讨论】:
为什么函数会返回 ('Ce', 'Arsenic') 为 True?它不应该返回 false,因为 order 是相反的 (ec)? 你测试过这个吗?它实际上返回 False。 确实返回 False!我想我已经运行了之前的执行。 此解决方案的一个问题是重复的if _ in test_string
.. 可能使用set
使其成为O(1)?
你的意思是set
?【参考方案6】:
递归是解决此类问题的最佳方法。 这是一个检查顺序的方法。
def sequentialOrder(test_string, control_string, len1, len2):
if len1 == 0: # base case 1
return True
if len2 == 0: # base case 2
return False
if test_string[len1 - 1] == control_string[len2 - 1]:
return sequentialOrder(test_string, control_string, len1 - 1, len2 - 1) # Recursion
return sequentialOrder(test_string, control_string, len1, len2-1)
test_string = 'Dih'
control_string = 'Danish'
print(isSubSequence(test_string, control_string, len(test_string), len(control_string)))
输出:
True
和False
test_string = 'Tbl'
control_string = 'Bottle'
这是一个做同样事情的迭代方法,
def sequentialOrder(test_string,control_string,len1,len2):
i = 0
j = 0
while j < len1 and i < len2:
if test_string[j] == control_string[i]:
j = j + 1
i = i + 1
return j==len1
test_string = 'Dih'
control_string = 'Danish'
print(sequentialOrder(test_string,control_string,len(test_string) ,len(control_string)))
【讨论】:
您介意详细说明 len1 和 len2 的功能吗?我刚开始学习python,对递归不熟悉。 递归并非特定于 python。它们是一种方法。我也会在一分钟内以迭代的方式编写它。 @VAnon 更新了我的答案。以上是关于检查一个字符串的字母在另一个字符串中是不是按顺序排列的主要内容,如果未能解决你的问题,请参考以下文章