給定以下字典:
dict_sports = {'Skateboarding': 163,
'Bowling': 134,
'Rugby': 83,
'Wrestling': 57,
'Baseball': 30,
'Badminton': 24,
'Volleyball': 22,
'Basketball': 18,
'Football': 16,
'Weightlifting': 15,
'Golf': 14,
'Skiing': 10,
'Boxing': 8,
'Cricket': 6}
total_sum = sum([v for k,v in dict_sports.items()])
print(total_sum)
我想把字典分成 3 個小字典;從而滿足以下條件:
三個字典各自值的總和;應該接近某個閾值;說在 200 的百分比加/減 %2.5 內。
即每個字典的值的總和應該是:
195 <= total_sum <= 205
這是我的解決方案,它解決了我原來的問題,但仍然與我上面提出的條件相矛盾,這可能是因為資料本身(不能以該精度進行拆分)...我的問題不在于拆分的準確性;我的問題是我必須為這個簡單的任務做大量的編碼!
list_01 = []
list_02 = []
list_03 = []
dict_01 = {}
dict_02 = {}
dict_03 = {}
for k,v in dict_sports.items():
if (sum(list_01) < 195) and (k not in dict_02) and (k not in dict_03):
list_01.append(v)
dict_01[k] = v
if sum(list_01) > 205:
list_01.pop()
dict_01.pop(k, None)
print(sum(list_01))
for k,v in dict_sports.items():
if (sum(list_02) < 195) and (k not in dict_01) and (k not in dict_03):
list_02.append(v)
dict_02[k] = v
if sum(list_02) > 205:
list_02.pop()
dict_02.pop(k, None)
print(sum(list_02))
for k,v in dict_sports.items():
if (sum(list_03) < 195) and (k not in dict_01) and (k not in dict_02):
list_03.append(v)
dict_03[k] = v
if sum(list_03) > 205:
list_03.pop()
dict_03.pop(k, None)
print(sum(list_03))
print(dict_01)
print(dict_02)
print(dict_03)
I would imagine that there is a much better way to approach this problem, maybe with pandas, or any other python library or a third-party library; or a better code than this!
uj5u.com熱心網友回復:
首先,您在這里描述的內容非常接近(或者是?)多重背包問題。有很多方法可以解決這個問題,具體取決于您對結果施加的條件。
我建議您閱讀此頁面以及與之相關的資源,以更好地構建您想要的輸出。例如,我們可以省略 items 嗎?如果我們不能用當前的專案串列滿足您對結果的約束(在 [195,205] 內)怎么辦?
使用純python,使用貪婪方法減少代碼量的天真方法可能是(假設您的字典按降序排序):
# Initialize a list of dictionaries to fill
dicts = [{},{},{}]
# Define a counter
i = 0
# Define your maximum value
max_value = 205
for k,v in dict_sports.items():
for i in range(len(dicts)):
if sum(dicts[i].values()) v < max_value:
dicts[i].update({k:v})
break
i =1
for d in dicts:
print("---- {} ----".format(sum(d.values())))
print(d)
給予
---- 203 ----
{'Skateboarding': 163, 'Baseball': 30, 'Skiing': 10}
---- 199 ----
{'Bowling': 134, 'Wrestling': 57, 'Boxing': 8}
---- 198 ----
{'Rugby': 83, 'Badminton': 24, 'Volleyball': 22, 'Basketball': 18, 'Football': 16, 'Weightlifting': 15, 'Golf': 14, 'Cricket': 6}
請注意,如果不滿足所有字典的總和條件,此解決方案可能會跳過專案。
uj5u.com熱心網友回復:
仔細觀察,三個 for 回圈的主體僅在變數名上有所不同。否則他們實作相同的演算法。這種代碼重復可以通過將演算法抽象為一個函式而不是重復三次來消除。
與其僅僅展示最終結果,我認為勾勒出實作目標的可能程序會更有用。
- 讓我們從簡單地將重復的代碼包裝在一個函式中開始:
list_01 = []
list_02 = []
list_03 = []
dict_01 = {}
dict_02 = {}
dict_03 = {}
def split_dict():
for k, v in dict_sports.items():
if (sum(list_01) < 195) and (k not in dict_02) and (k not in dict_03):
list_01.append(v)
dict_01[k] = v
if sum(list_01) > 205:
list_01.pop()
dict_01.pop(k, None)
split_dict()
print(sum(list_01))
#...
- 現在我們不希望我們的函式修改全域變數而是回傳計算結果:
def split_dict():
list_01 = []
dict_01 = {}
for k, v in dict_sports.items():
if (sum(list_01) < 195) and (k not in dict_02) and (k not in dict_03):
list_01.append(v)
dict_01[k] = v
if sum(list_01) > 205:
list_01.pop()
dict_01.pop(k, None)
return list_01, dict_01
list_01, dict_01 = split_dict()
- 如果我們想重用這個函式,我們需要在 if 條件中改變
dict_02and ,所以讓我們把它們變成引數:dict_03
def split_dict(dict_02, dict_03):
# ... unchanged code omitted for brevity
return list_01, dict_01
list_01, dict_01 = split_dict(dict_02, dict_03)
- 在本地和全域上使用相同的變數名是不好的做法,而且該函式應該在不同的情況下作業。因此,讓我們清理并使用更通用和更具描述性的名稱:
def split_dict(exclude_01, exclude_02):
selected_values = []
selected_items = {}
for k, v in dict_sports.items():
if (sum(selected_values) < 195) and (k not in exclude_01) and (k not in exclude_02):
selected_values.append(v)
selected_items[k] = v
if sum(selected_values) > 205:
selected_values.pop()
selected_items.pop(k, None)
return selected_values, selected_items
list_01, dict_01 = split_dict(dict_02, dict_03)
- 最后,我們可以通過使用不同的輸入和輸出變數在所有三個地方使用該函式:
list_01, dict_01 = split_dict({}, {})
print(sum(list_01))
list_02, dict_02 = split_dict(dict_01, {})
print(sum(list_02))
list_03, dict_03 = split_dict(dict_01, dict_02)
print(sum(list_03))
At this point, the amount of code is reduced by a factor close to 3. It also has the advantage that if you want to further tweak the algorithm there is only one place to change.
A few suggestions for next steps to take:
- Try to combine
exclude_01andexclude_02into a single function parameter - Change the hard coded numeric constants into function parameters
- Avoid subsequent append/pop by checking the sum first
- Come up with a new algorithm that satisfies the constraints even on later splits
- ...
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/436684.html
