Python单行代码实现列表追加非重复元素及问题排查
问题:列表去重并按顺序添加元素
原始需求:有两个列表,listA包含多个字典,listB为空。需要将listA中所有字典的键复制到listB中,仅当键不在listB中时才添加。
以下是可正常运行的循环实现代码:
listA = [{'A': 1, 'B': 2}, {'C': 3, 'D': 4, 'E': 5}, {'A': 26, 'Z': 1, 'D': 23}] listB = [] for i in listA: for key in i.keys(): if key not in listB: listB.append(key) print(listB)
输出结果:
['A', 'B', 'C', 'D', 'E', 'Z']
问题1:单行代码替换循环后得到生成器对象
用户尝试用单行代码替换循环,编写了如下代码,但输出的是生成器对象而非列表元素:
listA = [{'A': 1, 'B': 2}, {'C': 3, 'D': 4, 'E': 5}, {'A': 26, 'Z': 1, 'D': 23}] listB = [] listB.append(key for i in listA for key in i.keys() if key not in listB) print(listB)
输出结果:
[<generator object <genexpr> at 0x0000020AC0334120>]
解决方法
错误原因是append()会把传入的整个对象作为单个元素加入列表,生成器表达式被当成了一个元素。要实现需求,有两种简洁的单行方式:
方法1:使用extend()配合生成器表达式(保持原循环的实时判断逻辑)
listA = [{'A': 1, 'B': 2}, {'C': 3, 'D': 4, 'E': 5}, {'A': 26, 'Z': 1, 'D': 23}] listB = [] listB.extend(key for d in listA for key in d if key not in listB) print(listB)
extend()会迭代生成器中的每个元素,且生成器是惰性求值的,每次判断key not in listB时,listB已经包含之前添加的元素,因此能正确去重。
方法2:利用有序集合(Python3.7+,更简洁)
Python3.7及以上版本中,字典的键会保留插入顺序,因此可以用dict.fromkeys()快速生成无重复的有序键集合,再转为列表:
listA = [{'A': 1, 'B': 2}, {'C': 3, 'D': 4, 'E': 5}, {'A': 26, 'Z': 1, 'D': 23}] listB = list(dict.fromkeys(key for d in listA for key in d)) print(listB)
该方法直接通过字典自动去重,同时保留键的首次出现顺序,结果与原循环一致。
问题2:临时列表推导式的if条件未生效,出现重复元素
用户尝试用临时列表解决问题1,但仍出现重复元素:
listA = [{'A': 1, 'B': 2}, {'C': 3, 'D': 4, 'E': 5}, {'A': 26, 'Z': 1, 'D': 23}] listB = [] temp_list = [key for i in listA for key in i.keys() if key not in listB] listB.extend(temp_list) print(listB)
输出结果:
['A', 'B', 'C', 'D', 'E', 'A', 'Z', 'D']
原因解释
列表推导式是一次性完成所有元素的遍历和条件判断,在整个推导过程中,listB始终是初始的空列表。因此key not in listB对所有键都成立,所有键都会被加入temp_list,最终extend到listB时自然会出现重复项。而原循环是每次添加元素后都会更新listB,下一次判断时会基于更新后的listB进行,因此能正确去重。
内容的提问来源于stack exchange,提问作者Sarat Kota
相关产品推荐
相关产品推荐

