我正在努力想出办法解决这个问题(以及如何在stackoverflow上提出这个问题的名称)。
我需要以某种方式删除保留余数的字符串的共性。
给出如下列表:
l = ('first',
'first.second',
'first.second.third',
'a.b.c',
'x.y.z',
'x.y')
我希望列表输出为:
('first',
'second',
'third',
'a.b.c',
'x.y',
'z' )
您可以看到,当first.second
减去first
并保持second
时。我们从first.second
first.second.third
减去third
。 a.b.c
没有任何东西要从中减去,所以它仍然存在。从x.y
中扣除x.y.z
,z
仍然存在。
我想,也许sort(key=len)
将成为解决方案的一部分,以及某种递归结束字符串余数。我希望有一种干净的方法来删除列表中每个字符串的共性。
答案 0 :(得分:2)
我认为在编写解决方案之前,您需要更准确地定义问题。这是我从您的测试用例中推断的内容:
但问题是优先级是不明确的。例如,按以下顺序:
lst = ('a.b.c',
'a.b.d')
'a'和'b'在哪里?您的测试用例意味着共同成员应该转到具有最少共同成员的成员(因此“z”不会与“x.y.z”保持一致),但是有很多边缘情况需要考虑。您需要以更精确的格式提出要求。
采用更简单的规则,即“成员”应该保留在它出现的第一个位置,以下功能可以解决这个问题:
def remove_common(lst):
seen = set()
res = []
for i in lst:
members = i.split('.')
res.append('.'.join(w for w in members if w not in seen))
seen |= set(members)
return tuple(res)
这给你的结果非常接近:
>>> remove_common(l)
('first', 'second', 'third', 'a.b.c', 'x.y.z', '')
答案 1 :(得分:2)
如果输出顺序不重要,此解决方案将为您提供预期值。
这与实施几乎与@ brianpck的答案相同。但我使用排序来处理"x.y.z"
问题。还有一些额外的解释。
l = ('first',
'first.second',
'first.second.third',
'a.b.c',
'x.y.z',
'x.y')
def clarify(lst):
# Sort the list to deal with the order problem.
# for ex. "x.y.z" deletes "x.y" if not sorted
lst = sorted(lst)
# Words encountered.
words = set()
new_list = []
for elem in lst:
# Divide elements using dots.
divided = elem.split(".")
# New element to be added to the result.
new_elem = []
# For each word in a divided element.
for word in divided:
# If a word in the element is not encountered before.
# Add it to new element
# Add it to words
if word not in words:
new_elem.append(word)
words.add(word)
# Join new element
new_list.append(".".join(new_elem))
return new_list
print clarify(l)
# Gives ['a.b.c', 'first', 'second', 'third', 'x.y', 'z']
# You can make this a tuple in the solution as in the input if you want.
答案 2 :(得分:1)
我更多地考虑了这个有趣的问题并提出了解决方案。
问题基本上是树形的,无论你最终使用哪种树状技术:
我将使用以下扩展的单词列表列表,因为它指出了一些使其他解决方案失败的边缘情况:
li = ['First',
'FirstSecond',
'FirstSecondFirst',
'FirstSecondFirstly',
'FirstSecondThird',
'FirstFoo',
'FirstBarracudaSphyraena',
'xyz',
'xy',
'12345',
'123',
'1',
'FireTruckGarage',
'FireTruck',
'Fire']
诀窍在于注意到,每当前缀可能延长时,我们必须将前一个前缀保存在前缀堆栈上(此处称为prefixes
),其中包含到目前为止所见的所有前缀但是已经筋疲力尽了。在我们完成了一些“更深层”的词之后 - 在树的更深处的节点意义上 - 我们可能需要回溯并再次使用旧的前缀来替换一些较短的词。
在遇到没有当前前缀前缀的单词后,我们必须弹出前缀堆栈,直到我们找到 为该单词添加前缀并继续从那里开始。
def ambiguate(words):
output = {}
prefixes = ['']
prefix = prefixes[0]
for item in sorted(set(words)):
backtracked = False
while not item.startswith(prefix):
prefix = prefixes.pop()
backtracked = True
# If we have backtracked, we put back the current prefix onto the
# prefix stack since we may have to use it later on.
if backtracked:
prefixes.append(prefix)
# Construct new output and a new prefix and append it to the
# prefix stack
output[item] = item.replace(prefix, '', 1)
prefix = item
prefixes.append(prefix)
return output
运行:
print(ambiguate(li))
收率:
{'1': '1',
'123': '23',
'12345': '45',
'Fire': 'Fire',
'FireTruck': 'Truck',
'FireTruckGarage': 'Garage',
'First': 'First',
'FirstBarracudaSphyraena': 'BarracudaSphyraena',
'FirstFoo': 'Foo',
'FirstSecond': 'FirstSecond',
'FirstSecondFirst': 'First',
'FirstSecondFirstly': 'ly',
'FirstSecondFourth': 'Fourth',
'FirstSecondThird': 'FirstSecondThird',
'a': 'a',
'abc': 'bc',
'xy': 'xy',
'xyz': 'z'}
答案 3 :(得分:0)
我想也许我对列表和词典理解太过花哨了。
我相信我能用以下方法解决问题:
这是我到目前为止所拥有的:
li = [
'first',
'first.second',
'first.second.third',
'a',
'a.b',
'a.b.c',
'x.y.z',
'x.y']
li.sort()
prev_l = ''
output = {}
for l in li:
if l.find(prev_l) ==0:
output[l] = l.replace(prev_l,'')
else:
output[l] = l
prev_l = l
输出:
{
'a' : 'a',
'a.b' : '.b',
'a.b.c' : '.c',
'first' : 'first',
'first.second' : '.second',
'first.second.third' : '.third',
'x.y' : 'x.y',
'x.y.z' : '.z'}