如果列表中包含双字母组或三字母组,则删除列表中的单字母组 python

Get rid of unigrams in a list if contained within bigrams or trigrams python

假设我有一个 n-gram 列表,并且我想删除任何一元组,前提是它们已经包含在列表中的二元组或三元组中。

例如:

ngram_list = ["apple cider", "apple",  "cat man", "cat", "batman", "bat"]

我想结束的是:

ngram_list = ["apple cider", "cat man", "batman", "bat"]

在结果中 "apple" 被删除,因为它包含在二元组 "apple cider" 中, "cat" 被删除,因为它包含在二元组 "cat man" 中,但是 "bat" 仍然存在,因为即使 "bat" 在 "batman" 中,"batman" 也不是双字母组或三字母组。

我考虑解决这个问题的方法是只保留一元字母,循环遍历它们,然后在仅包含二元字母和三元字母的单独列表中搜索每个一元字母...但我只是想知道最有效的方法是什么?

我将首先遍历所有输入 ngram,将 unigram 与其余的分开,并从 (n+1)-gram 中构建一个 buzz "seen" unigram 列表,然后我将过滤输入它:

def clean_up(ngrams):
    seen = set()
    for ngram in ngrams:
        if ' ' in ngram:
            seen = seen.union(set(ngram.split()))
    return [ngram for ngram in ngrams if ngram not in seen]


print(clean_up(ngram_list))
# ['apple cider', 'cat man', 'batman', 'bat']

如果您的 (n+1)-grams 比 unigrams 多得多,您可以通过保存第一次迭代的一些结果来提高速度:

def clean_up2(ngrams):
    unigrams = []
    nplus1grams = []
    seen = set()
    for ngram in ngrams:
        if ' ' in ngram:
            nplus1grams.append(ngram)
            seen = seen.union(set(ngram.split()))
        else:
            unigrams.append(ngram)
    return nplus1grams + [unigram for unigram in unigrams if unigram not in seen]


print(clean_up(ngram_list))
# ['apple cider', 'cat man', 'batman', 'bat']

虽然这会需要更多的内存,而且它不会(通常)保留输入的顺序,但它会将所有(幸存的)unigrams 放在最后。