【问题标题】:Using python, how can I merge or join two lists so that their values don't overlap?使用 python,如何合并或连接两个列表,使它们的值不重叠?
【发布时间】:2011-12-24 03:32:50
【问题描述】:

首先,我为我的不准确词汇道歉。我是一个绝对零基础的初学者。无论如何,我正在尝试解决这个问题: http://projecteuler.net/problem=1

简而言之,我正在尝试编写一个脚本,该脚本将找到 1000 以下的所有 3 或 5 的倍数之和。

我的(非常基本的)方法是使用这个程序:

##Multiples of 3
x = range(3, 1000, 3)

##Multiples of 5
y = range(5, 1000, 5)

a = sum(x)
b = sum(y)
n = a + b

print n

我意识到这是错误的,因为像 15 这样的数字包含两次(它是 5 和 3 的倍数)。 那么有没有办法解决这个问题,还是我从一个完全错误的角度来解决这个问题? 还是在尝试解决这个问题之前我需要学习更多? 如果这在之前的帖子中已经解释过,我也很抱歉,但我环顾了一下。

【问题讨论】:

  • 需要保留订单吗?
  • 因为我只需要总和,我很确定顺序不会影响我的结果。
  • 啊,对。我没有足够重视这个问题。 set 应该可以正常工作。
  • 解决问题后,请务必阅读未锁定的论坛以获取此问题的答案。有比利用set 行为更优雅、更有效的方法。
  • 哇。我检查了其他人的解决方案,但我缺乏经验来理解其中的任何一个。他们都在使用我从未听说过的功能。解决方案越复杂越好吗?我想这些类型的解决方案更好地展示了你的能力,对吧?好吧,我现在会满足于我的简单。

标签: python list range


【解决方案1】:

这叫做包含排除原则,所以你可以这样做

##Multiples of 3
x = range(3, 1000, 3)

##Multiples of 5
y = range(5, 1000, 5)

##multiple of 15 are counted twice
z=range(15,1000,15)


a = sum(x)
b = sum(y)
c = sum(z)
n = a + b -c
print(n)

但美在于使用生成器或列表推导

a = sum(i for i in range(1000) if i%3 == 0 or i%5 == 0 )
print(a)

其中 % 是 modulo 并且是整数除法中的余数。 这样做的好处是代码读起来很流畅,是规则的直接翻译,可以从左到右阅读。

两种算法的运行时间都取决于 n 在这种情况下是 1000。如果 n 是例如 1000000000,您将不得不等待很长时间才能完成。如果你应用一点数学,你会发现

sum(a for a in range(a1,a2,n)) 

实际上是arithmetic progression,无论n有多大,都可以在常数时间内计算出总和。 http://en.wikipedia.org/wiki/Project_Euler#Example_problem_and_solutions

【讨论】:

  • 啊,我明白了。哇,我真的很喜欢你的解决方案。我从来没有想过只有 15 的倍数是重复的。我不应该感到惊讶。我还在上中学,我的数学还不算太高。但再次感谢!
【解决方案2】:

您可以使用set 来消除重复项:

>>> len(x)
333
>>> len(y)
199
>>> s = set(x + y)
>>> len(s)
532

然后你可以sum集合的成员来代替。

【讨论】:

    【解决方案3】:

    简单方法:

    sum(set(x+y))

    sets 具有相当多的功能,您会发现它们对 PE 问题很有用。

    你也可以很容易地在整个范围内使用一个简单的循环来做到这一点。

    【讨论】:

    • 非常感谢!效果很好!虽然,老实说,我几乎不知道“设置”功能是做什么的。我显然有很多东西要学,但无论如何,再次感谢!
    • @Grant,set 函数在其他列表上创建一组操作。现在,由于集合元素不重复,如果它在创建集合时遇到重复实体,它只保留其中一个。
    • 为@AbhranilDas 的评论添加更多内容:set 以无序的方式将您 add 的每个元素存储到它恰好一次,并进行诸如“is a in x”之类的操作或“x 中的所有内容,但 y 中的所有内容”快速简单。在这种情况下,我们利用了所有东西都是唯一存储的:它可以只存在一次。我链接到python文档,如果您有任何问题,请随时告诉我们^_^
    • 所以本质上,一个集合相当于一个列表,但它没有重复的“实体”?等待。这不可能。哈哈,我想我只是去阅读python的文档。无论如何,谢谢。
    【解决方案4】:

    您正在寻找sets

    ##Multiples of 3
    x = range(3, 1000, 3)
    
    ##Multiples of 5
    y = range(5, 1000, 5)
    
    x = list(set(x) - set(y))
    

    根据您的操作,您必须更改代码。以上从x 中删除了y 中的所有内容。它就像列表,但您可以对项目进行算术运算。

    【讨论】:

      【解决方案5】:

      要合并排序的序列,您可以使用heapq.merge:

      import heapq
      print list(heapq.merge(xrange(3, 20, 3), xrange(5, 20, 5)))
      # -> [3, 5, 6, 9, 10, 12, 15, 15, 18]
      

      要删除重复项,您可以使用 unique_justseen recipe from itertools documentation:

      print list(unique_justseen([3, 5, 6, 9, 10, 12, 15, 15, 18]))
      # -> [3, 5, 6, 9, 10, 12, 15, 18]
      

      在这种情况下,unique_justseen() 可以简化为:

      from itertools import groupby, imap
      from operator  import itemgetter
      
      def unique_justseen(iterable):
          return imap(itemgetter(0), groupby(iterable))
      

      这些函数不需要输入参数是序列。它们接受任意迭代(包括无限),例如,生成 3 或 5 的倍数的无限序列:

      import heapq
      from itertools import count, takewhile
      
      m3, m5 = count(3, 3), count(5, 5) 
      m3_5 = heapq.merge(m3, m5)
      uniq_m3_5 = unique_justseen(m3_5) # *all* unique multiples of 3 or 5
      

      要找到解决方案:

      print sum(takewhile(lambda x: x < 1000, uniq_m3_5))
      # -> 233168
      # check that it is correct
      print sum(set(range(3, 1000, 3) + range(5, 1000, 5)))
      # -> 233168
      print sum(x for x in xrange(1000) if x % 3 == 0 or x % 5 == 0)
      # -> 233168
      print sumk(3, 1000) + sumk(5, 1000) - sumk(15, 1000)
      # -> 233168
      

      sumk() 在哪里:

      def sumk(k, n):
          m = (n-1)//k
          return k*m*(m+1)//2
      

      公式来自the Wikipedia link,由@ralu提供。

      【讨论】:

        【解决方案6】:

        我不知道这是否效率较低,但是制作两个集合并对其进行布尔运算以删除重复项似乎是多余的,因为集合的定义是

        an unordered collection of distinct hashable objects
        (强调)

        所以只需将两个范围都添加到一个集合中,然后让“创建”该集合删除重复项:

        sum(set(range(3, 1000, 3) + range(5, 1000, 5)))
        

        【讨论】:

          猜你喜欢
          • 2022-06-13
          • 1970-01-01
          • 2016-10-14
          • 1970-01-01
          • 2021-06-23
          • 1970-01-01
          • 2013-06-24
          • 1970-01-01
          • 2014-01-04
          相关资源
          最近更新 更多