从python中的列表中删除一些重复项

时间:2019-07-04 07:09:34

标签: python

更新:我相信我找到了解决方案。我把它放在最后。

假设我们有以下列表:

a = ['a', 'a', 'b', 'b', 'a', 'a', 'c', 'c']

我想创建另一个列表,以从列表a中删除重复项,但同时,保持比率不变,并保持顺序。 输出应为:

b = ['a', 'b', 'a', 'c']

编辑:为了更好地解释,该比率不必完全完整。所需要做的就是为数据中的所有字母输出一个单个字母。但是,两个字母可能相同,但是代表了两个不同的事物。正如我稍后所说,计数对于识别这一点很重要。代表一个唯一变量的字母的计数介于3000-3400之间,因此当我将总数除以3500并四舍五入时,我知道最后应该出现多少次,但是问题是我不知道它们应该按什么顺序排列在。

为了说明这一点,我将再添加一个输入和所需的输出:

  • 输入:['a','a','a','a','b','b','c','c','c','a','a', 'd','d','a','a']
  • 所需的输出:['a','a','b','c','a','d','a']

请注意,“ C”已重复了3次。比率不必精确保留,我只需要表示该变量被表示多少次,并且由于在此示例中该变量仅被表示3次,因此不足以将其计为2。 唯一的区别是,这里我假设所有重复正好重复两次的字母都是唯一的,尽管在数据集中,唯一性还是取决于外观3000-3400次。

注意(1):不一定要考虑这一点,但是有可能并非所有字母都可以很好地分组在一起,例如,考虑4个字母的唯一性以使其简短:['a',' a','b','a','a','b','b','b','b']仍应表示为['a','b']。但是,在这种情况下,这是一个小问题。

编辑: 我尝试并成功完成的示例:

full_list = ['a', 'a', 'b', 'b', 'a', 'a', 'c', 'c'] 
#full_list is a list containing around 10k items, just using this as example
rep = 2 # number of estimated repetitions for unique item, 
# in the real list this was set to 3500

quant = {'a': 0, "b" : 0, "c" : 0, "d" : 0, "e" : 0, "f" : 0, "g": 0}
for x in set(full_list):
    quant[x] = round(full_list.count(x)/rep)


final = []

for x in range(len(full_list)):
    if full_list[x] in final:
        lastindex = len(full_list) - 1 - full_list[::-1].index(full_list[x])

        if lastindex == x and final.count(full_list[x]) < quant[full_list[x]]:
            final.append(full_list[x])
    else:
        final.append(full_list[x])
print(final)

我上面的代码有两个问题:

  • 如果同一数据的重复次数超过2次,则不会正确计数它们。例如:['a','a','b','b','a','a','c','c','a','a']应成为['a' ,'b','a','c','a'],但改为[[a','b,'c','a']
  • 这需要很长时间才能完成,因为我敢肯定这是一个非常重要的过程 效率低下的方法。

最后一句话:我尝试过的代码更多地是为了在最普通的输入上实现所需的输出,但是并不能完全达到我的预期。同样重要的是要注意输入随时间变化。单个字母的重复并不总是相同的,尽管我相信它们总是组合在一起的,所以我在考虑制作一个标记,该标记在击中一个字母时会变为True,并在更改为另一个字母后立即变为false,但这还有一个问题,就是无法解释两个相同的字母可能会紧挨在一起的事实。每个字母作为一个字母的总计数始终在3000-3400之间,因此我知道,如果该计数超过该数字,则该数量将大于1。

更新:解决方案 遵循hiro主角的建议,并进行了一些修改,以下代码似乎有效:


full = ['a', 'a', 'b', 'b', 'a', 'a', 'c', 'c', 'a', 'a']
from itertools import groupby
letters_pre = [key for key, _group in groupby(full)]
letters_post = []
for x in range(len(letters_pre)):
    if x>0 and letters_pre[x] != letters_pre[x-1]:
        letters_post.append(letters_pre[x])
    if x == 0:
        letters_post.append(letters_pre [x])
print(letters_post)

唯一的问题是,它不认为有时字母可以出现在唯一的字母之间,如“ Note(1)”中所述,但这只是一个很小的问题。更大的问题是,例如,同一字母的两个单独出现是连续的(例如,两个以唯一性为例)是不连续的:['a','a','a','a','b当所需的输出应为['a','a','b']

时,','b']变为['a','b']

2 个答案:

答案 0 :(得分:2)

这是itertools.groupby派上用场的地方:

from itertools import groupby

a = ["a", "a", "b", "b", "a", "a", "c", "c"]

res = [key for key, _group in groupby(a)]
print(res)  # ['a', 'b', 'a', 'c']

这是一个您可以“缩小”唯一键的版本(但保证结果中至少有一个):

from itertools import groupby, repeat, chain

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'a', 'a',  
     'd', 'd', 'a', 'a']
scale = 0.4

key_count = tuple((key, sum(1 for _item in group)) for key, group in groupby(a))
# (('a', 4), ('b', 2), ('c', 5), ('a', 2), ('d', 2), ('a', 2))

res = tuple(
    chain.from_iterable(
        (repeat(key, round(scale * count) or 1)) for key, count in key_count
    )
)
# ('a', 'a', 'b', 'c', 'c', 'a', 'd', 'a')

可能有更聪明的方法来确定scale(可能基于输入列表a的长度和平均group的长度)。

答案 1 :(得分:1)

可能是一个奇怪的人,但是:

b = []
for i in a:
    if next(iter(b[::-1]), None) != i:
        b.append(i)
print(b)

输出:

['a', 'b', 'a', 'c']