日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

Python 从列表中选取任意个元素求和

發(fā)布時(shí)間:2023/12/15 综合教程 36 生活家
生活随笔 收集整理的這篇文章主要介紹了 Python 从列表中选取任意个元素求和 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、問(wèn)題

碰到一個(gè)比較好玩的問(wèn)題,我有許多小額的發(fā)票,需要從這些發(fā)票中湊出一個(gè)指定的整數(shù)來(lái)。怎么去實(shí)現(xiàn)呢?

二、規(guī)劃求解

在excel中,有一個(gè)功能是“規(guī)劃求解”,具體可以參看鏈接:規(guī)劃求解。
規(guī)劃求解怎么算的,我也不知道,我們來(lái)看看用python怎么實(shí)現(xiàn)。

三、python實(shí)現(xiàn)

這些小額發(fā)票,我們可以用一個(gè)列表來(lái)表示。比如a = [1, 3, 5, 6, 8]。那么這個(gè)列表的元素可能產(chǎn)生多少種組合呢?由于列表里面每一個(gè)元素都可能有,也可能沒(méi)有。所以這里面就有2的5次方種變化。代碼驗(yàn)證(ps:代碼參考CSDN)。

a = [1, 3, 5, 6, 8]
all_subset = [[]]
for i in range(len(a)):
    for j in range(len(all_subset)):
        all_subset.append(all_subset[j]+[a[i]])
print(all_subset)
print(len(all_subset))  # 32

似乎我只需要對(duì)上面的二維數(shù)組里面每一個(gè)元素,即一維數(shù)組求和即可。列表中有5個(gè)數(shù),有32種可能性,這么操作可行。但是,假如是10個(gè)數(shù)則有1024(2的10次方)種可能性,20個(gè)數(shù)就有1048576(2的20次方)種可能性,30個(gè)數(shù)則有1073741824(2的30次方)種可能性。組合的可能性可是指數(shù)翻番,電腦根本存不下這么長(zhǎng)的列表。那就得再想其它辦法。

現(xiàn)在的問(wèn)題是,在沒(méi)有這個(gè)長(zhǎng)列表的情況下,我怎么去遍歷這些所有組合呢。我們用多層嵌套的方式求解。

a = [1, 3, 5, 6, 8]
ran2 = range(2)
sum = 0
for d0 in ran2:
    for d1 in ran2:
        for d2 in ran2:
            for d3 in ran2:
                for d4 in ran2:
                    data = a[0]*d0 + a[1]*d1 + a[2]*d2 + a[3]*d3 + a[4]*d4
                    sum += 1
print(sum)  # 32

這樣我們就不用存這個(gè)長(zhǎng)列表,只要把每一個(gè)data跟設(shè)定的總數(shù)進(jìn)行對(duì)比即可。但是問(wèn)題又來(lái)了,如果給了我30張發(fā)票,我要寫30個(gè)嵌套循環(huán)嗎?那畫面簡(jiǎn)直無(wú)法想象。

我們注意到,列表里面每個(gè)元素,只有兩種狀態(tài),即有和沒(méi)有。那么可以再創(chuàng)建一個(gè)列表,表示狀態(tài),0表示沒(méi)有,1表示有。即

a = [1, 3, 5, 6, 8]
coefficient = [0, 0, 0, 0, 0]

這樣就只需要更改coefficient里面每個(gè)元素的狀態(tài)即可。為了實(shí)現(xiàn)coefficient這個(gè)列表各種可能性,我們可以采用把數(shù)字轉(zhuǎn)為二進(jìn)制,然后將二進(jìn)制數(shù)每個(gè)數(shù)字位分開的方式。
代碼如下。

a = [1, 3, 5, 6, 8]
for i in range(0, 2**len(a)):
    coefficient = list(str(bin(i))[2:].rjust(len(a), '0'))
    print(coefficient)

結(jié)果如下:

['0', '0', '0', '0', '0']
['0', '0', '0', '0', '1']
['0', '0', '0', '1', '0']
['0', '0', '0', '1', '1']
['0', '0', '1', '0', '0']
....
['1', '1', '1', '1', '0']
['1', '1', '1', '1', '1']

這樣就只需要把列表a和列表coefficient的每個(gè)元素相乘累加即可。

四、代碼

最后呈現(xiàn)的代碼如下,我有29張發(fā)票,要求得到的值是180。

#!/usr/bin/env python
# coding=utf-8

import time
from functools import reduce

# 原列表
nums = [1.68, 37.27, 14.78, 12.84, 15.26, 4.86, 10.06, 25.6, 8.42, 20.27,
        6.46, 29.68, 6.13, 18.48, 4.98, 7.88, 4.77, 8.61, 5.75, 4.3, 7.76,
        3.13, 11.11, 5.1, 2.91, 3.55, 6.45, 55.27, 8.76]

# 期待求和的值
expect_data = 180

# 對(duì)數(shù)組進(jìn)行排序
nums.sort()

# 縮小數(shù)組范圍,將比設(shè)定值大的元素拋棄
narrow_nums = []
for i in nums:
    if i > expect_data:
        break
    narrow_nums.append(i)

# 把數(shù)組倒序
narrow_nums.sort(reverse=True)

start_time = time.time()

# 開始計(jì)算
for i in range(0, 2**len(narrow_nums)):
    # 將循環(huán)的值轉(zhuǎn)變?yōu)閰?shù)列表
    nums_coefficient = list(str(bin(i))[2:].rjust(len(narrow_nums), '0'))
    # 將參數(shù)列表和原數(shù)組進(jìn)行乘積運(yùn)算得到新的列表
    combine_list = list(map(lambda x: x[0] * int(x[1]), zip(narrow_nums, nums_coefficient)))
    # 對(duì)列表進(jìn)行求和取值
    sumdata = reduce(lambda x, y: x + y, combine_list)
    if abs(sumdata - expect_data) < 1e-6:
        print(list(filter(lambda x: x > 0, combine_list)))
        break

end_time = time.time()
print('運(yùn)算了{(lán)}次,耗時(shí){}'.format(i, round(end_time - start_time, 2)))

以下是結(jié)果:

[20.27, 18.48, 14.78, 12.84, 11.11, 10.06, 8.76, 8.61, 8.42, 7.88, 7.76, 6.46, 6.45, 5.75, 5.1, 4.98, 4.86, 4.77, 4.3, 3.55, 3.13, 1.68]
運(yùn)算了29359101次,耗時(shí)591.0

五、總結(jié)

介紹了如何將多層嵌套轉(zhuǎn)化為一維數(shù)組進(jìn)行運(yùn)算
本文采用暴力破解,耗時(shí)較久。拋磚引玉,歡迎大家留言,提供節(jié)省時(shí)間復(fù)雜度的算法。

總結(jié)

以上是生活随笔為你收集整理的Python 从列表中选取任意个元素求和的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。