[英]How can I drop strings contained in other string contained in the same string list?
[英]Python: Remove Strings in a List that are contained by at least one other String in the same List
我想通過以下方式過濾我的字符串列表:如果同一列表中至少有一個其他字符串“在”它,我想排除 strings 。 或以不同的方式把這個:我想保持的字符串,如果是在它的同一列表的任何其他字符串。 如果可能,區分大小寫應該在這里發揮作用。
為了更清楚地說明這一點,請在下面找到一個示例:
我的“第一個”列表包含每個字符串:
elements =["tree","TREE","treeforest","water","waterfall"]
應用解決方案后,我很想收到此列表:
elements = ["tree","TREE","water"]
例如: tree
在treeforest
。 因此, treeforest
被排除在我的列表之外。 同樣適用於water
和waterfall
。 但是,應該維護tree
, TREE
和water
,因為沒有其他字符串“在”它們。
由於我想將此應用於“更大”的字符串列表,因此首選更有效的解決方案。
希望這是可以理解的。 非常感謝提前! 任何幫助都受到高度贊賞。
相當優化的函數,帶有 2 個循環,節省了大量的循環迭代:
def filterlist(l):
# keep track of elements, which will be deleted
deletelist = [False for _ in l]
for i, el in enumerate(l):
# already in deletelist, jump right to the next el
if deletelist[i]:
continue
for j, el2 in enumerate(l):
# comparing item to itself or el2 already in deletelist?
# jump to next el2
if i == j or deletelist[j]:
continue
# the comparison everyone expects
if el in el2:
deletelist[j] = True
# also, check the other way around
# will save loop iterations later
elif el2 in el:
deletelist[i] = True
break # causes jump to next el
# create new list, keep elements that are not in deletelist
return [el for i, el in enumerate(l) if not deletelist[i]]
通常內置函數更快,所以讓我們將其與 Ed Ward 的解決方案進行比較:
# result of Ed Ward's solution using timeit:
100000 loops, best of 10: 5.38 usec per loop
# filterlist function with loops using timeit:
100000 loops, best of 10: 4.42 usec per loop
有趣,但要獲得真正具有代表性的結果,您應該使用更大的元素列表運行 timeit。
from copy import deepcopy
def remove_composite_words(e,elements):
temp = [x for x in elements if e in x]
temp = set(temp)
elements = list(set(elements).difference(temp))
return e,sorted(elements, key=len)
def keep_shortest_root(elements):
elements = deepcopy(elements)
elements = list(set(elements))
elements = sorted(elements, key=len)
if len(elements[0]) ==0:
elements = elements[1:]
results = []
e = elements[0]
while elements:
e,elements = remove_composite_words(e,elements)
results.append(e)
if elements:
e = elements[0]
return results
elements =["tree","TREE","treeforest","water","waterfall",'forestTREE','tree']
keep_shortest_root(elements)
這應該返回
['tree', 'TREE', 'water']
這個怎么運作:
函數remove_composite_words()
測試一個元素是否包含在列表中的任何其他元素中,並只保存那些匹配的元素。 然后它從初始列表中刪除匹配的元素。
因此,如果您有元素'a'
和列表['a','aa','b','c']
該函數將返回'a'
和列表['b','c']
。
keep_shortest_root()
將remove_composite_words()
keep_shortest_root()
應用於初始列表,然后應用於轉換后的列表(來自remove_composite_words()
輸出),直到沒有更多單詞為止。
請注意, keep_shortest_root()
首先從輸入列表中獲取唯一的單詞,然后按長度對它們進行排序。 這與remove_composite_words()
從初始列表中刪除匹配單詞的事實相結合,使算法運行得更快,因為比較次數隨着迭代次數而下降。
為已經提供的解決方案找到了一些更簡單的解決方案,我想我可能會加入
def Remove_Subset(List):
ListCopy=List
for Element1 in List:
for Element2 in List:
if (Element1 in Element2) and (Element1!= Element2):
ListCopy.remove(Element2)
return(ListCopy)
elements =["treeforest","tree","TREE","treeforest","water","waterfall","tree"]
print(Remove_Subset(elements))
>>> ['tree', 'TREE', 'water']
這是我在評論中給出的答案的解釋
我使用了這個代碼:
new_elements = list(filter(lambda item: not any(elem in item for elem in elements if elem != item), elements))
產生:
['tree', 'TREE', 'water']
我不知道你對 Python 生成器表達式和filter
了解多少,所以我還是盡量解釋一下。
filter
是一個 Python 內置函數,它需要一個函數來在提供的可迭代對象(例如列表等)中的每個項目上使用。 在我們的例子中,函數是這樣的:
lambda item: not any(elem in item for elem in elements if elem != item)
此函數從列表 ( item
) 中獲取一個項目,然后遍歷列表中的每個元素 ( for elem in elements
),並為每個元素 ( elem
) 檢查該元素是否在我們的字符串 ( item
) 中。 請注意, if elem != item
,它會跳到下一個元素,因為我們不想將它與自身進行比較。
函數any
只是不斷迭代,直到返回的表達式為True
,或者到達結尾。 如果有任何匹配項, any
返回True
,但要告訴filter
刪除此項,我們需要返回False
,因此我們反轉any
的輸出。
我們還通過filter
我們的列表( elements
),並將結果從filter
轉換為另一個list
。
注意:使用any
而不是迭代每個其他項目的每個項目的好處是,在找到匹配項的情況下,我們不必迭代整個列表:此時any
返回。 理論上,這可能比沒有break
語句的兩個嵌套 for 循環更快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.