删除列表中第一次出现n次后的子列表

4

我有一个嵌套的长列表。每个子列表包含2个元素。我想做的是遍历整个列表,并在找到第一个元素超过3次后删除子列表。

示例:

ls = [[1,1], [1,2], [1,3], [1,4], [2,2], [2,3], [3,4], [3,5], [3,6], [3,7]]

desired_result = [[1,1], [1,2], [1,3], [2,2], [2,3], [3,4], [3,5], [3,6]]

欢迎来到SO。请花点时间阅读http://stackoverflow.com/help/how-to-ask。它将帮助您制定扎实的问题,有望获得有用的答案。 - orde
1
请在回答中包含您尝试过的内容(可以编辑并包含一些代码),并解释您尝试失败的原因。 - Basj
输入的第一个元素是否总是已排序的? - Dani Mesejo
7个回答

1
如果输入已按第一个元素排序,您可以使用groupbyislice
from itertools import groupby, islice
from operator import itemgetter

ls = [[1, 1], [1, 2], [1, 3], [1, 4], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6], [3, 7]]

result = [e for _, group in groupby(ls, key=itemgetter(0)) for e in islice(group, 3)]
print(result)

输出

[[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6]]

这个想法是使用groupby按第一个值对元素进行分组,然后使用islice获取前三个值(如果存在)。


0

可能不是最短的答案。

这个想法是在迭代ls时计算出现次数。

from collections import defaultdict

filtered_ls = []
counter = defaultdict(int)
for l in ls: 
    counter[l[0]] += 1
    if counter[l[0]] > 3:
        continue
    filtered_ls += [l]
print(filtered_ls)
# [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6]]

0
如果列表已经排序,您可以使用 itertools.groupby 然后只保留每个组的前三个项目。
>>> import itertools
>>> ls = [[1,1], [1,2], [1,3], [1,4], [2,2], [2,3], [3,4], [3,5], [3,6], [3,7]]
>>> list(itertools.chain.from_iterable(list(g)[:3] for _,g in itertools.groupby(ls, key=lambda i: i[0])))
[[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6]]

0
你可以像下面这样做:
ls = [[1,1], [1,2], [1,3], [1,4], [2,2], [2,3], [3,4], [3,5], [3,6], [3,7]]

val_count = dict.fromkeys(set([i[0] for i in ls]), 0)

new_ls = []
for i in ls:
    if val_count[i[0]] < 3:
        val_count[i[0]] += 1 
        new_ls.append(i)

print(new_ls)

输出:

[[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6]]

0

您可以使用collections.defaultdict在O(n)时间内按第一个值进行聚合。然后使用itertools.chain构建一个列表的列表。

from collections import defaultdict
from itertools import chain

dd = defaultdict(list)
for key, val in ls:
    if len(dd[key]) < 3:
        dd[key].append([key, val])

res = list(chain.from_iterable(dd.values()))

print(res)

# [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 4], [3, 5], [3, 6]]

0

Ghillas BELHADJ的回答很好。但是你应该考虑使用defaultdict来完成这个任务。这个想法来自于Raymond Hettinger,他建议在分组和计数任务中使用defaultdict。

from collections import defaultdict

def remove_sub_lists(a_list, nth_occurence):
    found = defaultdict(int)
    for sublist in a_list:
        first_index = sublist[0]
        print(first_index)
        found[first_index] += 1
        if found[first_index] <= nth_occurence:
            yield sublist

max_3_times_first_index = list(remove_sub_lists(ls, 3)))

0
这里有一个不使用任何模块的选项:
countDict = {}

for i in ls:
    if str(i[0]) not in countDict.keys():
        countDict[str(i[0])] = 1
    else:
        countDict[str(i[0])] += 1
        if countDict[str(i[0])] > 3:
            ls.remove(i)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接