【问题标题】:Removing List from List of Lists with condition从有条件的列表列表中删除列表
【发布时间】:2017-01-15 20:17:10
【问题描述】:

我有这个项目列表,我想从最后一个项目开始逐个删除它,直到它达到预算的总价值 = 325.000

from collections import namedtuple

Item = namedtuple('Item', 'region sector name budget target performance'.split())

sorted_KP = [Item(region='H', sector='2', name='H3', budget=7000.0, target=1.0, performance=4.0),
Item(region='H', sector='2', name='H10', budget=35000.0, target=15.0, performance=1.0),
Item(region='I', sector='2', name='I6', budget=50000.0, target=5.0, performance=0.40598931548848194),
Item(region='E', sector='4', name='E5', budget=75000.0, target=30.0, performance=0.0663966081766),
Item(region='C', sector='1', name='C1', budget=75000.0, target=50.0, performance=0.0308067750379),
Item(region='C', sector='1', name='C2', budget=75000.0, target=50.0, performance=0.0308067750379),
Item(region='C', sector='5', name='C4', budget=75000.0, target=50.0, performance=0.0308067750379),
Item(region='I', sector='2', name='I5', budget=100000.0, target=5.0, performance=0.40598931548848194),
Item(region='E', sector='4', name='E1', budget=100000.0, target=30.0, performance=0.0663966081766),
Item(region='D', sector='5', name='D21', budget=60000.0, target=4.0, performance=0.2479775110248),
Item(region='D', sector='5', name='D30', budget=10000.0, target=1.0, performance=0.1653183406832),
Item(region='D', sector='1', name='D23', budget=30000.0, target=20.0, performance=0.023659703723372342),
Item(region='C', sector='5', name='C3', budget=150000.0, target=75.0, performance=0.0308067750379),
Item(region='D', sector='5', name='D20', budget=30000.0, target=5.0, performance=0.0826591703416),
Item(region='H', sector='2', name='H6', budget=310576.0, target=1.0, performance=4.0),
Item(region='H', sector='3', name='H5', budget=9500.0, target=1.0, performance=0.1172008400616),
Item(region='E', sector='6', name='E3', budget=100000.0, target=30.0, performance=0.03747318294316411),
Item(region='G', sector='3', name='G17', budget=75000.0, target=20.0, performance=0.04132095963602382),
Item(region='C', sector='4', name='C5', budget=75000.0, target=25.0, performance=0.0308067750379),
Item(region='C', sector='2', name='C6', budget=30000.0, target=5.0, performance=0.0616135500758),
Item(region='C', sector='2', name='C7', budget=30000.0, target=5.0, performance=0.0616135500758),
Item(region='D', sector='6', name='D22', budget=65190.0, target=30.0, performance=0.020332158889648923),
Item(region='D', sector='5', name='D3', budget=100000.0, target=20.0, performance=0.0413295851708),
Item(region='D', sector='5', name='D4', budget=100000.0, target=20.0, performance=0.0413295851708),
Item(region='A', sector='1', name='A12', budget=25000.0, target=25.0, performance=0.00749432996938),
Item(region='A', sector='1', name='A13', budget=25000.0, target=25.0, performance=0.00749432996938),
Item(region='A', sector='3', name='A25', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='5', name='A26', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='1', name='A27', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='1', name='A29', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='3', name='A30', budget=4500.0, target=1.0, performance=0.02997731987752)]

但是除了总价值之外,我还有两个关于该项目是否应该删除的条件。

首先,删除该项目后,列表列表中仍至少保留一个代表相同区域

的项目

其次,在项目被删除后,仍然至少有一个项目代表相同的部门

例如,我可以删除最后一个项目,因为它代表区域“A”,剩下 5 个项目也代表区域“A”。它也代表扇区“3”,剩下 3 个项目代表扇区“3”。

重复此移除和检查,直到我达到移除总预算至少 325.000

我做了这段代码,但我无法得到我需要的东西。请帮我改正。

from collections import Counter
unpack = []
for item in sorted_KP:
    item_budget = item[3]
    sum_unpack = sum(item[3] for item in unpack)
    budget = 325000

    remaining = []
    for item in sorted_KP:
         if item not in unpack:
             remaining.append(item)

    region_el = [item[0] for item in remaining]
    counter_R_el = Counter(region_el)

    sector_el = [item[1] for item in remaining]
    counter_S_el = Counter(sector_el)

    if counter_R_el >= 1 or counter_S_el >= 1:
        if sum_unpack <= budget:
            unpack.append(item)

for item in unpack:
    print "\t", item

这是我的代码得到的结果,item-25 不应该被删除:

unpack =Item(region='A', sector='3', name='A30', budget=4500.0, target=1.0, performance=0.02997731987752)
    Item(region='A', sector='1', name='A29', budget=4500.0, target=1.0, performance=0.02997731987752)
    Item(region='A', sector='1', name='A27', budget=4500.0, target=1.0, performance=0.02997731987752)
    Item(region='A', sector='5', name='A26', budget=4500.0, target=1.0, performance=0.02997731987752)
    Item(region='A', sector='3', name='A25', budget=4500.0, target=1.0, performance=0.02997731987752)
    Item(region='A', sector='1', name='A13', budget=25000.0, target=25.0, performance=0.00749432996938)
    Item(region='A', sector='1', name='A12', budget=25000.0, target=25.0, performance=0.00749432996938)
    Item(region='D', sector='5', name='D4', budget=100000.0, target=20.0, performance=0.0413295851708)
    Item(region='D', sector='5', name='D3', budget=100000.0, target=20.0, performance=0.0413295851708)
    Item(region='D', sector='6', name='D22', budget=65190.0, target=30.0, performance=0.020332158889648923)

Item-25(项目名称:“A12”)不能被删除,即使我们还有预算要删除,因为如果它被删除,将不再有代表区域“A”的项目,依此类推.

虽然解决方案应该是:

unpack = [Item(region='A', sector='3', name='A30', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='1', name='A29', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='1', name='A27', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='5', name='A26', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='3', name='A25', budget=4500.0, target=1.0, performance=0.02997731987752),
Item(region='A', sector='1', name='A13', budget=25000.0, target=25.0, performance=0.00749432996938),
Item(region='D', sector='5', name='D4', budget=100000.0, target=20.0, performance=0.0413295851708),
Item(region='D', sector='5', name='D3', budget=100000.0, target=20.0, performance=0.0413295851708),
Item(region='D', sector='6', name='D22', budget=65190.0, target=30.0, performance=0.020332158889648923),
Item(region='C', sector='2', name='C7', budget=30000.0, target=5.0, performance=0.0616135500758)]

提前感谢您的帮助

【问题讨论】:

  • namedtuples 的一个好处是您可以使用 dot notation 访问属性,而不必使用索引 - 例如i = Item(...); i.budget
  • if counter_R_el &gt;= 1 or counter_S_el &gt;= 1: 在我运行它时抛出 TypeError - 它试图将 Counter() 与 int() 进行比较 - 这是您的实际代码吗?

标签: python list conditional-statements


【解决方案1】:

假设您使用的是 Python 2,就像您使用 print 而不使用 ()

查看修改后代码中的cmets:

unpack = []
for item in sorted_KP[::-1]: # loop the items in reverse order
    #item_budget = item[3] # variable not used
    sum_unpack = sum(item[3] for item in unpack)
    budget = 325000

    remaining = []
    for x in sorted_KP: # don't use 'item' here as in Python 2, it will modify the variable 'item' in the outer loop
        if x not in unpack:
            remaining.append(x)

    region_el = [x[0] for x in remaining] # don't use 'item' here as well
    counter_R_el = Counter(region_el)

    sector_el = [x[1] for x in remaining] # don't use 'item' here as well
    counter_S_el = Counter(sector_el)

    #if counter_R_el >= 1 or counter_S_el >= 1: # note that result is always True in Python 2
    if counter_R_el[item.region] > 1 and counter_S_el[item.sector] > 1: # check '> 1' instead of '>= 1', and use 'and' instead of 'or'
        if sum_unpack <= budget:
            unpack.append(item)

for item in unpack:
    print "\t", item

我提出的解决方案:

budget = 325000
sum = 0 # accumulated budget of removed items
removed_KP = [] # holds the removed items
for item in sorted_KP[::-1]:
    # stop checking if over-budget
    if sum >= budget: break
    # check whether there are items with same region and sector
    rcnt = scnt = 0
    for tmp in sorted_KP:
        if tmp.region == item.region: rcnt += 1
        if tmp.sector == item.sector: scnt += 1
    if scnt > 1 and rcnt > 1:
        # this item can be removed based on the constraints
        sorted_KP.remove(item)
        removed_KP.append(item)
        sum += item.budget

# print the removed items
for item in removed_KP:
    print(item)

【讨论】:

  • 非常感谢,它真的对我有帮助...还有你的笔记^^d
【解决方案2】:

当我实际尝试运行它时更新答案,我发现了其他一些问题:

  • 内部for item in sorted_KP 使用与外部循环相同的item 计数器并覆盖它 - 总是试图删除A30(最后一个)项
  • 在内循环中切换到 item2 时,我还必须反转外循环顺序(即从最后一行开始删除)。
  • 区域/扇区计数器比较不正确,导致TypeError: unorderable types: Counter() &gt;= int() - 需要根据需要选择与项目所在区域或扇区匹配的特定计数
  • 合并了我之前的回答:你需要and你的两个额外条件,而不是or他们
  • 包含@wwii 的评论 - 实际上计数器比较需要是&gt; 1,而不是&gt;= 1

实际测试代码:

>>> for item in sorted_KP[::-1]:
...     item_budget = item[3]
...     sum_unpack = sum(item[3] for item in unpack)
...     budget = 325000
...     remaining = []
...     for item2 in sorted_KP:
...          if item2 not in unpack:
...              remaining.append(item2)
...     region_el = [item[0] for item in remaining]
...     counter_R_el = Counter(region_el)
...     sector_el = [item[1] for item in remaining]
...     counter_S_el = Counter(sector_el)
...     if counter_R_el[item.region] > 1 and counter_S_el[item.sector] > 1:
...         if sum_unpack <= budget:
...             unpack.append(item)
... 
>>> 
>>> for item in unpack:
...    logging.error(item)
... 
ERROR:root:Item(region='A', sector='3', name='A30', budget=4500.0, target=1.0, performance=0.02997731987752)
ERROR:root:Item(region='A', sector='1', name='A29', budget=4500.0, target=1.0, performance=0.02997731987752)
ERROR:root:Item(region='A', sector='1', name='A27', budget=4500.0, target=1.0, performance=0.02997731987752)
ERROR:root:Item(region='A', sector='5', name='A26', budget=4500.0, target=1.0, performance=0.02997731987752)
ERROR:root:Item(region='A', sector='3', name='A25', budget=4500.0, target=1.0, performance=0.02997731987752)
ERROR:root:Item(region='A', sector='1', name='A13', budget=25000.0, target=25.0, performance=0.00749432996938)
ERROR:root:Item(region='D', sector='5', name='D4', budget=100000.0, target=20.0, performance=0.0413295851708)
ERROR:root:Item(region='D', sector='5', name='D3', budget=100000.0, target=20.0, performance=0.0413295851708)
ERROR:root:Item(region='D', sector='6', name='D22', budget=65190.0, target=30.0, performance=0.020332158889648923)
ERROR:root:Item(region='C', sector='2', name='C7', budget=30000.0, target=5.0, performance=0.0616135500758)
>>> 

【讨论】:

  • 另外,条件应该是&gt; 1而不是&gt;= 1??
【解决方案3】:

我无法轻松地整理您的代码。 if counter_R_el &gt;= 1 or counter_S_el &gt;= 1: 只是无法工作,您无法将 Counter() 与 int() 进行比较。看起来你在循环套件中不断地重新制作/重置事物,这变得令人困惑。

你似乎在正确的轨道上。

  • 跟踪区域和扇区集合的数量。Counter() 是一个不错的选择。
  • 查看列表中的每个项目,并检查它是否符合您的限制条件
  • 如果删除,更新计数器和总成本

这是我想出的:

import collections, operator
Item = collections.namedtuple('Item', ['region', 'sector', 'name',
                                       'budget', 'target', 'performance'])

a = [Item(region='H', sector='2', name='H3', budget=7000.0, target=1.0, performance=4.0),
     Item(region='H', sector='2', name='H10', budget=35000.0, target=15.0, performance=1.0),
     Item(region='I', sector='2', name='I6', budget=50000.0, target=5.0, performance=0.40598931548848194),
     .....]

budget = 325000

# sort highest to lowest cost
a.sort(key = operator.attrgetter('budget'), reverse = True)
project_cost = sum(item.budget for item in a)
# constraint counters
region_count = collections.Counter(item.region for item in a)
sector_count = collections.Counter(item.sector for item in a)

# iterate over a copy of the list
b = a.copy()
for item in b:
    if project_cost <= budget:
        break
    # check item against constraints
    if region_count[item.region] > 1 and sector_count[item.sector] > 1:
        # remove the item from the original list 
        a.remove(item)
        # uodate the counters and cost
        region_count[item.region] -= 1
        sector_count[item.sector] -= 1
        project_cost -= item.budget

a 包含满足约束且总成本低于预算的项目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-23
    • 1970-01-01
    • 2018-10-13
    • 2020-01-23
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多