簡體   English   中英

列表中夫婦產品的總和

[英]sum of products of couples in a list

我想找出清單中夫妻產品的總和。 例如,給出了一個列表[1, 2, 3, 4] 我想得到的是答案= 1*2 + 1*3 + 1*4 + 2*3 + 2*4 + 3*4

我使用蠻力來做,這給了我很大列表的超時錯誤。 我想要一種有效的方法來做到這一點。 請告訴我,我該怎么做?

這是我的代碼,可以正常工作,但是我需要更高效的代碼:

def proSum(list):
    count  = 0
    for i in range(len(list)- 1):
        for j in range(i + 1, len(list)):
            count +=  list[i] * list[j]
    return count

這里是:

In [1]: def prodsum(xs):
   ...:     return (sum(xs)**2 - sum(x*x for x in xs)) / 2
   ...: 

In [2]: prodsum([1, 2, 3, 4]) == 1*2 + 1*3 + 1*4 + 2*3 + 2*4 + 3*4
Out[2]: True

xs = a1, a2, .., an ,然后

(a1+a2+...+an)^2 = 2(a1a2+a1a3+...+an-1an) + (a1^2+...+an^2)

所以我們有

a1a2+...+an-1an = {(a1+a2+...+an)^2 - (a1^2+...+an^2)}/2


比較@georg方法和我的方法的性能

結果和測試代碼如下(使用的時間越少越好): 在此處輸入圖片說明

In [1]: import timeit

In [2]: import matplotlib.pyplot as plt

In [3]: def eastsunMethod(xs):
   ...:     return (sum(xs)**2 - sum(x*x for x in xs)) / 2
   ...: 

In [4]: def georgMethod(given):
   ...:     sum = 0
   ...:     res = 0
   ...:     cur = len(given) - 1
   ...: 
   ...:     while cur >= 0:
   ...:         res += given[cur] * sum
   ...:         sum += given[cur]
   ...:         cur -= 1
   ...:     return res
   ...: 

In [5]: sizes = range(24)

In [6]: esTimes, ggTimes = [], []

In [7]: for s in sizes:
   ...:     t1 = timeit.Timer('eastsunMethod(xs)', 'from __main__ import eastsunMethod;xs=range(2**%d)' % s)
   ...:     t2 = timeit.Timer('georgMethod(xs)', 'from __main__ import georgMethod;xs=range(2**%d)' % s)
   ...:     esTimes.append(t1.timeit(8))
   ...:     ggTimes.append(t2.timeit(8))

In [8]: fig, ax = plt.subplots(figsize=(18, 6));lines = ax.plot(sizes, esTimes, 'r', sizes, ggTimes);ax.legend(lines, ['Eastsun', 'georg'], loc='center');ax.set_xlabel('size');ax.set_ylabel('time');ax.set_xlim([0, 23])

使用itertools.combinations生成唯一對:

# gives [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
unique_pairs = list(itertools.combinations([1, 2, 3, 4], 2))

然后使用列表推導獲得每對的乘積:

products = [x*y for x, y in unique_pairs] # => [2, 3, 4, 6, 8, 12]

然后使用sum您的產品:

answer = sum(products) # => 35

可以像下面這樣將它們全部包裹在一起:

answer = sum(x*y for x,y in itertools.combinations([1, 2, 3, 4], 2))

在使它成為單行的情況下, combinations的結果而不將其強制轉換為list 同樣,列表理解周圍的括號也被丟棄,將其轉換為生成器表達式

注意Eastsun的答案georg的答案使用更好的算法,並且對於大型列表而言,它們的表現很容易超過我的答案。

注意@Eastsun的答案實際上更好。

這是解決該問題的另一種更“算法”的方法。 觀察給定的

a 0 ,a 1 ,..., n

期望的總和是(由於分配法則)

a 0 (a 1 + a 2 + ... + a n )+ a 1 (a 2 + a 3 + ... + a n )+ ... + a n-2 (a n-1 + a n )+ a n-1 a n

這導致以下算法:

  • sum為0, current為最后一個元素
  • 在每一步
    • sumcurrent相乘並加到結果中
    • 加上currentsum
    • current是以前的current

在python中:

sum = 0
res = 0
cur = len(given) - 1

while cur >= 0:
    res += given[cur] * sum
    sum += given[cur]
    cur -= 1

print res

沒有外部庫,您可以使用maplambda來成對計算* ,然后將所有內容sum

l=[1, 2, 3, 4]
sum(map(lambda x,y:x*y, l, l[1:]+[l[0]]))

但是由於您正在處理大數據,因此建議您使用numpy。

import numpy as np

l = np.array([1, 2, 3, 4])

print sum(l*np.roll(l, 1))
# 24

編輯:跟上OP的更新問題

import numpy as np

l = [1, 2, 3, 4]
sums = 0
while l:
    sums+=sum(l.pop(0)*np.array(l))

print sums
#35

因此,它要做的是取出list的第一個元素,其余為* 重復進行直到沒有任何東西可以從列表中取出。

def sumOfProductsOfCouples(l):返回sum(l [i-1] * l [i],代表inumerate(l)中的i,n)

from itertools import combinations
l=[1, 2, 3, 4]
cnt=0
for x in combinations(l,2):
    cnt+=x[0]*x[1]
print (cnt)

輸出;

>>> 
35
>>> 

combinations()會根據需要提供配對。 然后進行計算。

像這樣調試 ;

l=[1, 2, 3, 4]
for x in combinations(l,2):
    print (x)

>>> 
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
>>> 

看到您的一對在這里。 實際上,您會找到這些combinations pairs.的總和combinations pairs.

使用itertools模塊中的permutations方法:

from itertools import *

p = permutations([1, 2, 3, 4], 2) # generate permutations of two
p = [frozenset(sorted(i)) for i in p] # sort items and cast 
p = [list(i) for i in set(p)] # remove duplicates, back to lists

total = sum([i[0] * i[1] for i in p]) # 35 your final answer

您可以使用地圖,求和函數。

>>> a = [1, 2, 3, 4]
>>> sum(map(sum, [map(lambda e: e*k, l) for k, l in zip(a, (a[start:] for start, _ in enumerate(a, start=1) if start < len(a)))]))
35

將以上表達分為幾部分,

>>> a = [1, 2, 3, 4]
>>> c = (a[start:] for start, _ in enumerate(a, start=1) if start < len(a))
>>> sum(map(sum, [map(lambda e: e*k, l) for k, l in zip(a, c)]))
35

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM