【问题标题】:How to remove numbers from a list which contain repeated digits?如何从包含重复数字的列表中删除数字?
【发布时间】:2021-04-17 21:00:38
【问题描述】:

我正在尝试解决以下问题:

我有一个给定范围内很长的整数列表,其中大多数包含重复数字的数字,如下例所示。

[123456, 889756, 854123, 997886, 634178]

我的目标是删除具有重复数字的那些或获得一个新列表,其中的数字只有不同的数字:

[123456, 854123, 634178]

有什么好方法可以做到这一点吗?非常感谢您!

【问题讨论】:

  • 一种简单的方法(但可能不是“好”)是将数字转换为字符串,然后将其转换为一组字符。如果 set 和 string 具有相同的“len”,则其中没有重复的数字。您必须将此测试应用于循环或列表推导中的每个列表项。
  • 2 分钟前发布了具有这种精确技术的答案...
  • @VexenCrabtree Stack Overflow 的 Android 应用有一些更新延迟。

标签: python list algorithm


【解决方案1】:

您可以在数字的字符串表示上使用set 来查看有多少位进入了集合。如果这与原始数字的位数相同,则通过测试:

lst = [123456, 889756, 854123, 997886, 634178]
result = [n for n in lst if len(set(str(n))) == len(str(n))]

print(result)

如下所述,基准测试证实对临时变量执行内联赋值是有利的:

result = [n for n in lst if len(set(s := str(n))) == len(s)]

【讨论】:

  • Python 在这种事情上不是很棒吗:-)
  • 在我的问题中测试了这段代码,它运行良好!非常感谢您的帮助!
  • @Vexen, true, str 被调用了两次,但我不明白如何避免调用len 两次而不恢复到更昂贵的逻辑。我认为,如果数字在合理范围内,str 的双重调用的开销很小,并且添加一个临时变量以某种方式避免它也是有代价的。传统的for 循环必须调用append,这比列表理解要慢。尽管有两次str 调用,我认为它不会胜过列表理解。
  • 也许:= 运营商会在这里提供帮助:result = [n for n in lst if len(set(s := str(n))) == len(s)]
  • @AndrejKesely,也许......要进行基准测试。
【解决方案2】:

另一个解决方案,re:

import re

r = re.compile(r"(\d).*\1")
lst = [123456, 889756, 854123, 997886, 634178]

lst = [i for i in lst if not r.search(str(i))]
print(lst)

打印:

[123456, 854123, 634178]

编辑:小基准:

from timeit import timeit


lst = [123456, 889756, 854123, 997886, 634178] * 10000


def re_method(lst):
    r = re.compile(r"(\d).*\1")
    return [i for i in lst if not r.search(str(i))]


def trincot1(lst):
    return [n for n in lst if len(set(str(n))) == len(str(n))]


def trincot2(lst):
    return [n for n in lst if len(set(s := str(n))) == len(s)]


def afaalgo(lst):
    answer = []
    for value in lst:
        value = str(value)
        new_list = []
        for nums in value:
            new_list.append(nums)
        if sorted(list(set(new_list))) == sorted(new_list):
            answer.append(int(value))
    return answer


t1 = timeit(lambda: re_method(lst), number=10)
t2 = timeit(lambda: trincot1(lst), number=10)
t3 = timeit(lambda: trincot2(lst), number=10)
t4 = timeit(lambda: afaalgo(lst), number=10)

print(t1)
print(t2)
print(t3)
print(t4)

在我的机器上打印 (3700x/Python 3.8.5):

0.2806989410019014
0.33745980000821874
0.263871792005375
0.8039937680005096

所以在这种情况下,set():= 的版本是最快的。

【讨论】:

  • 我在 PyPy 中使用您的基准添加了一个答案。
【解决方案3】:

当使用 PyPy 时,这似乎比其他的大约 2 to 7 times faster

def has_duplicates(n):
  s = 0
  while n:
    d = n % 10
    if (1<<d) & s:
      return True
    s |= 1<<d
    n = n // 10
  return False
 
def f(lst):
  return [i for i in lst if not has_duplicates(i)]

【讨论】:

  • 感谢 PyPy 版本和基准测试! +1
【解决方案4】:

这是一些伪代码(不是在 Python 中):

newList <- []
for each number in oldList
  if hasNoRepeatDigits(number)
    newList.add(number)
  endif
endfor

【讨论】:

    【解决方案5】:
    lst = [123456, 889756, 854123, 997886, 634178]
    
    answer = []
    for value in lst:
        value = str(value)
        new_list = []
        for nums in value:
            new_list.append(nums)
        if sorted(list(set(new_list))) == sorted(new_list):
            answer.append(int(value))
    print(answer)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-16
      • 2019-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多