给定一组包含数字的字符串,我如何找到那些超集的字符串。例如,如果字符串'139 24'和'139 277 24'出现,那么我想保持'139 277 24'为'139 24'可以在其中找到。这些数字也可以以字符串内的任何顺序出现。
'24'
'277'
'277 24'
'139 24'
'139 277 24'
'139 277'
'139'
'136 24'
'136 277 24'
'136 277'
'136'
'136 139 24'
'136 139 277 24'
'136 139 277'
'136 139'
'246'
以下数据的结果如下。
'136 139 277 24'
'246'
编辑:我正在拆分每个字符串并将单个数字放在一个集合中,然后通过从整个列表创建的集合进行比较。我可以使用这种方法找到解决方案,但我认为应该有一些其他优雅的方法来执行相同的操作。
我正在尝试以下代码,并认为它变得越来越不复杂。
#First create a set of tuples
allSeqsTuple = set()
for seq in allSeqs: #allSeqs store the sequences described above
x = seq.split()
allSeqsTuple.add(tuple(x))
#For each 'allSeqs', find if all the items in that seq that is in 'allSeqsTuple'.
for line in allSeqs:
x = set(line.split())
result = findContainment(x, allSeqsTuple)
......
......
def findContainment(x, allSeqsTuple):
contained = False
for y in allSeqsTuple:
cntnd = bool(x-set(y))
if (cntnd):
contained = True
continue
else:
break
return contained
答案 0 :(得分:6)
让我们列出这个问题中主要参与者的清单:
'24 139 277'
<=
集合运算符set(['24', '139', '277'])
我们获得了一个字符串列表,但我们真正喜欢的是什么 - 更有用的 - 是一组集合:
In [20]: strings = [frozenset(s.split()) for s in strings]
In [21]: strings
Out[21]:
[frozenset(['24']),
frozenset(['277']),
...
frozenset(['136', '139']),
frozenset(['246'])]
冷冻的原因很快就会显现出来。我将在下面解释原因。我们想要集合的原因是因为它有一个方便的超集比较运算符:
In [22]: frozenset(['136']) <= frozenset(['136', '139', '24'])
Out[22]: True
In [23]: frozenset(['136']) <= frozenset(['24', '277'])
Out[23]: False
这正是我们需要确定一个字符串是否是另一个字符串的超字符串。
所以,基本上,我们想:
superstrings = set()
for s in strings
。s
中的每个strings
时,我们会添加新的superstrings
superstrings
如果它们不是已经存在的项目的子集
s
。对于每个superstrings
,请遍历一组for sup in superstrings
:s <= sup
。
检查s
是否sup
是s
的子集,退出循环,因为sup <= s
小于某个已知超级字符串。
检查是否s
- 即if
superstrings
superstrings
中某个项目的超集。在这种情况下,请移除s
中的项目并将其替换为superstrings
。
技术说明:
因为我们要从superstrings
删除项目,所以我们也不能
迭代for sup in superstrings.copy():
本身。所以,相反,迭代副本:
superstrings
strings
成为一组集合。但
集合中的项目必须是可以清除的,而集合中的项目则不是
哈希的。但是冻结了,所以有可能有一套
frozensets。这就是我们将frozensets
转换为列表的原因
strings = [
'24', '277', '277 24', '139 24', '139 277 24', '139 277', '139', '136 24',
'136 277 24', '136 277', '136', '136 139 24', '136 139 277 24', '136 139 277',
'136 139', '246']
def find_supersets(strings):
superstrings = set()
set_to_string = dict(zip([frozenset(s.split()) for s in strings], strings))
for s in set_to_string.keys():
for sup in superstrings.copy():
if s <= sup:
# print('{s!r} <= {sup!r}'.format(s = s, sup = sup))
break
elif sup < s:
# print('{sup!r} <= {s!r}'.format(s = s, sup = sup))
superstrings.remove(sup)
else:
superstrings.add(s)
return [set_to_string[sup] for sup in superstrings]
print(find_supersets(strings))
。['136 139 277 24', '246']
产量
def using_sorted(strings):
stsets = sorted(
(frozenset(s.split()) for s in strings), key=len, reverse=True)
superstrings = set()
for stset in stsets:
if not any(stset.issubset(s) for s in superstrings):
superstrings.add(stset)
return superstrings
In [29]: timeit find_supersets(strings)
100000 loops, best of 3: 18.3 us per loop
In [25]: timeit using_sorted(strings)
10000 loops, best of 3: 24.9 us per loop
事实证明这比预先排序字符串更快:
{{1}}
答案 1 :(得分:0)
假设您的字符串位于名为“strings”的列表中:
stset_string = {frozenset(s.split()):s for s in strings}
stsets = sorted(stset_string, key=len, reverse=True)
superstsets = set()
for stset in stsets:
if not any(stset.issubset(s) for s in superstsets):
superstsets.add(stset)
superstrings = [stset_string[s] for s in superstsets]
这会创建一个字典,将字符串中的标记集映射到原始字符串,确定哪些标记集对应于您的超弦,然后查找原始字符串。注意,如果有多个不同的字符串产生相同的标记,则将使用任意字符串来定义超字符串;你可能想要修改它以获得例如所有可能的超弦组。