【问题标题】:Removing list elements than are made of the same numbers删除由相同数字组成的列表元素
【发布时间】:2019-07-06 07:49:29
【问题描述】:

我有一个 python 程序,它输出这样的列表:

['0007', '0016', '0025', '0034', '0043', '0052', '0061', '0070', '0106', '0115', '0124', '0133', '0142', '0151', '0160', '0205', '0214', '0223', '0232', '0241', '0250', '0304', '0313', '0322', '0331', '0340', '0403', '0412', '0421', '0430', '0502', '0511', '0520', '0601', '0610', '0700', '1006', '1015', '1024', '1033', '1042', '1051', '1060', '1105', '1114', '1123', '1132', '1141', '1150', '1204', '1213', '1222', '1231', '1240', '1303', '1312', '1321', '1330', '1402', '1411', '1420', '1501', '1510', '1600', '2005', '2014', '2023', '2032', '2041', '2050', '2104', '2113', '2122', '2131', '2140', '2203', '2212', '2221', '2230', '2302', '2311', '2320', '2401', '2410', '2500', '3004', '3013', '3022', '3031', '3040', '3103', '3112', '3121', '3130', '3202', '3211', '3220', '3301', '3310', '3400', '4003', '4012', '4021', '4030', '4102', '4111', '4120', '4201', '4210', '4300', '5002', '5011', '5020', '5101', '5110', '5200', '6001', '6010', '6100', '7000']

理论上它不包含任何重复项,但它包含由相同元素(3 个零和 1 个七)组成的元素,例如 '0007' 和 '7000',标准过滤脚本不会捕获它们。如何制作一个而不是删除它们? 经过咨询,发现不需要保留订单,因此您的解决方案效果很好,谢谢大家

(如果我的帖子是重复的,那么我很抱歉,但我找不到任何相同的问题。请链接一个解决方案)

【问题讨论】:

  • 可以用一些正则表达式魔法吗?
  • 您的程序会认为00160601(例如)相等吗?
  • 这很容易做到,但是我们返回的是哪个值,00077000 以及 @Aquarthur 问题也很相关
  • 您可以为每个字符串定义一个集合,并与其他字符串的集合进行比较,以检查它们是否包含相同的数字。
  • @Aquarthur no,0016 和 0601 对我来说是重复的,

标签: python list duplicates


【解决方案1】:

使用set()消除重复,然后使用sorted()按照原始列表顺序排序。

l = ['0007', '0016', '0025', '0034', '0043', '0052', '0061', '0070', '0106', '0115',  '0124', '0133', '0142', '0151', '0160', '0205', '0214', '0223', '0232', '0241', '0250', '0304', '0313', '0322', '0331', '0340', '0403', '0412', '0421', '0430', '0502', '0511', '0520', '0601', '0610', '0700', '1006', '1015', '1024', '1033', '1042', '1051', '1060', '1105', '1114', '1123', '1132', '1141', '1150', '1204', '1213', '1222', '1231', '1240', '1303', '1312', '1321', '1330', '1402', '1411', '1420', '1501', '1510', '1600', '2005', '2014', '2023', '2032', '2041', '2050', '2104', '2113', '2122', '2131', '2140', '2203', '2212', '2221', '2230', '2302', '2311', '2320', '2401', '2410', '2500', '3004', '3013', '3022', '3031', '3040', '3103', '3112', '3121', '3130', '3202', '3211', '3220', '3301', '3310', '3400', '4003', '4012', '4021', '4030', '4102', '4111', '4120', '4201', '4210', '4300', '5002', '5011', '5020', '5101', '5110', '5200', '6001', '6010', '6100', '7000']

sorted(list(set(''.join(sorted(x)) for x in l)), key=lambda x: l.index(x))

# ['0007', '0016', '0025', '0034', '0115', '0124', '0133', '0223', '1114', '1123', '1222']

【讨论】:

  • 你偷了我的答案,但我会等到 OP 回答发布的两个重要问题
  • 它必须保留订单,检查 OP 的帖子这不会起作用
  • 现在怎么样,更好?
  • 当然,这是最直接最容易理解的答案
【解决方案2】:

您可以使用sorted 按字典顺序对字符串进行排序以创建唯一条目,然后您可以将其存储在字典中以便快速查找

some_filter = {} # will create a lookup table for unique combinations of chars
filtered_results = [] # contain the final results

for x in result:
    hashable = "".join(sorted(x))
    if not some_filter.get(hashable):
        filtered_results.append(x)
        some_filter[hashable] = True

print(filtered_results)

【讨论】:

  • if not some_filter.get(sorted(x)) 行中有错误,它不可散列
【解决方案3】:

您应该将您的元素转换为对于"0007""7000" 等输入相等 的元素。首先想到的是计数器。然后将您的元素放入set(),这将删除您所有的双打:

from collections import Counter

input_elements = ['0007', '0016', '0025', '0034', '0043', '0052', '0061',
                  '0070', '0106', '0115', '0124', '0133', '0142', '0151',
                  '0160', '0205', '0214', '0223', '0232', '0241', '0250',
                  # ...
                  '7000']
s = set(Counter(e) for e in input_elements)

现在s 将包含一组所有的 input_elements 并删除了双精度值。

不幸的是,Counters 是不可散列的(真可惜)。所以你可以使用 Counters 的元组版本:

s = set(tuple(Counter(e).items()) for e in input_elements)

我能想到的最漂亮的方法是创建你自己的字符串类,它具有这个特定的属性,当它们具有相同的数字时,无论它们的顺序如何,它们都被认为是相等的:

class OrderIrrelevantString(str):
  def __hash__(self):
    return hash(''.join(sorted(self)))
  def __eq__(self, other):
    return sorted(self) == sorted(other)

使用它你可以这样做:

s = set(OrderIrrelevantString(e) for e in input_elements)

然后结果将是一组OrderIrrelevantStrings,它们的外观和行为就像普通字符串一样,因此您可能可以立即将它们用于您想对它们做的任何事情。

【讨论】:

  • 这里有明显的语法错误,Counter 不是可哈希类型
  • @aws_apprentice 这远非语法错误 ;-) 但请参阅我的编辑以解决该问题。
  • 您的输出看起来与我认为 OP 想要的相差甚远
  • 你可能是对的。但这是他提供的输入的规范形式。诸如数字排序版本之类的东西很可能是他在输入中没有的东西。
  • 我添加了另一个版本,它使用特殊的字符串子类以我能想到的最佳方式实现这一目标。
【解决方案4】:

如果您不介意以不同顺序的元素列表结尾,这里有一个想法:

lst = [ ... your input ... ]
uniques = list({''.join(sorted(n)) for n in lst})

解释:

  • 输入中的每个字符串都被视为已排序的字符列表,以将不同顺序的相同组合视为相同大小写
  • 之后,我们将每个列表重新连接成一个字符串
  • 我们使用集合推导删除重复项
  • 最后,我们将所有内容转换回列表

结果如下:

['0016', '0124', '1222', '0115', '0034', '0025', '0223', '0007', '1123', '1114', '0133']

如果您确实想只保留元素的第一次出现,我们可以这样做,但会降低性能:

result = []
for n in lst:
    unique = ''.join(sorted(n))
    if unique not in result:
        result.append(n)

result
=> ['0007', '0016', '0025', '0034', '0115', '0124', '0133', '0223', '1114', '1123', '1222']

【讨论】:

  • 这是错误的,没有保留OP指定的顺序
  • @aws_apprentice 我在一开始就对此作出免责声明。这个问题很难维持秩序
  • @ÓscarLópez 实际上,基于原始索引的列表中的sorted() 将是一个简单的修复:)
  • @Idlehands 我们是否保证输入已排序?我不这么认为
  • @aws_apprentice 我添加了一个保留顺序的替代答案
【解决方案5】:

使用set 来检查是否已经访问过,同时保持顺序。它将过滤掉在考虑 '0007''7000' 之前已经看到的元素,并且在集合中我们可以保持 07 的计数,而不是元素本身

l = ['0007', '0016', '0025', '0034', '0043', '0052', '0061', '0070', '0106', '0115',  '0124', '0133', '0142', '0151', '0160', '0205', '0214', '0223', '0232', '0241', '0250', '0304', '0313', '0322', '0331', '0340', '0403', '0412', '0421', '0430', '0502', '0511', '0520', '0601', '0610', '0700', '1006', '1015', '1024', '1033', '1042', '1051', '1060', '1105', '1114', '1123', '1132', '1141', '1150', '1204', '1213', '1222', '1231', '1240', '1303', '1312', '1321', '1330', '1402', '1411', '1420', '1501', '1510', '1600', '2005', '2014', '2023', '2032', '2041', '2050', '2104', '2113', '2122', '2131', '2140', '2203', '2212', '2221', '2230', '2302', '2311', '2320', '2401', '2410', '2500', '3004', '3013', '3022', '3031', '3040', '3103', '3112', '3121', '3130', '3202', '3211', '3220', '3301', '3310', '3400', '4003', '4012', '4021', '4030', '4102', '4111', '4120', '4201', '4210', '4300', '5002', '5011', '5020', '5101', '5110', '5200', '6001', '6010', '6100', '7000']

from collections import Counter
s=set()
new_list=[]
for i in l:
    if tuple(Counter(sorted(i,key=int)).items()) in s:
        pass
    else:
        s.add(tuple(Counter(sorted(i,key=int)).items()))
        new_list.append(i)

输出:

['0007',
 '0016',
 '0025',
 '0034',
 '0115',
 '0124',
 '0133',
 '0223',
 '1114',
 '1123',
 '1222']

【讨论】:

    【解决方案6】:

    您可以遍历列表并将每个元素添加到集合中,在将元素添加到集合之前,您应该检查元素/反向元素是否已经存在。这将消除您的问题

    my_list = ['0007', '7000']
    final = set()
    for item in my_list:
        if item not in final and item[::-1] not in final:
            final.add(item)
    final = list(final)
    print(final) 
    # output: ['0007']
    

    【讨论】:

    • 当然,希望更好
    猜你喜欢
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    • 2015-06-12
    • 2013-04-12
    • 2014-01-31
    • 1970-01-01
    相关资源
    最近更新 更多