根据标准对项目进行分组

时间:2016-09-08 19:11:44

标签: python python-3.x

我有一个项目列表:

ShelvesToPack = [{'ShelfLength': 2278.0, 'ShelfWidth': 356.0, 'ShelfArea': 759152.0, 'ItemNames': 1},
{'ShelfLength': 1220.0, 'ShelfWidth': 610.0, 'ShelfArea': 372100.0, 'ItemNames': 2},
{'ShelfLength': 2310.0, 'ShelfWidth': 762.0, 'ShelfArea': 1760220.0, 'ItemNames': 3},
{'ShelfLength': 610.0, 'ShelfWidth': 610.0, 'ShelfArea': 1450435.0, 'ItemNames': 4}]

我需要一个程序来说明一个人可以拥有的最小组数以及这些项的分组方式。

我想形成这些项目的组,使得项目的货架长度之和<=最大长度或项目的货架宽度之和&lt; =最大宽度和项目的ShelfArea的总和&lt; =最大面积。在这种情况下,如果我们查看逻辑,我们可以将所有项目包装在最少2个组中 - 项目1和3将形成一个组,项目2和&amp; 4将形成其他组。我希望得到以下格式的答案:

[[{'ShelfLength': 2278.0, 'ShelfWidth': 356.0, 'ShelfArea': 759152.0, 'ItemNames': 1} ,
 {'ShelfLength': 2310.0, 'ShelfWidth': 762.0, 'ShelfArea': 1760220.0, 'ItemNames': 3}],
[{'ShelfLength': 1220.0, 'ShelfWidth': 610.0, 'ShelfArea': 372100.0, 'ItemNames': 2},
 , {'ShelfLength': 610.0, 'ShelfWidth': 610.0, 'ShelfArea': 1450435.0, 'ItemNames': 4}]]

我已经写了一段代码,但它没有给出我想要的结果。

ShelvesToPack_sorted = sorted(ShelvesToPack, key = itemgetter('ShelfWidth'), reverse = True)
AreaOfObject = 2972897.28
current_width = 0
current_length = 0
current_area = 0
ply =[]
plywoods=[]
for item in ShelvesToPack_sorted:
    if (current_width + item['ShelfWidth'] <= 1219.2  or  current_length + item['ShelfLength'] <= 2438.5) and  current_area + item['ShelfArea'] <= AreaOfObject:
        ply.append(item)
        current_width += item['ShelfWidth']
        current_length += item['ShelfLength']
        current_area += item['ShelfArea']
    else:
       plywoods.append(ply)
       if (item['ShelfWidth'] <= 1219.2  or item['ShelfLength'] <= 2438.5) and item['ShelfArea'] <= AreaOfObject:
           ply = [item]
           current_width = item['ShelfWidth']
           current_length = item['ShelfLength']
           current_area = item['ShelfArea']
       else:
           ply = []
           current_width = 0
           current_length = 0
           current_area = 0

if ply:
    plywoods.append(ply)

print(plywoods)

我有以下输出,这是不对的,我无法进行正确的分组。

[[{'ItemNames': 3, 'ShelfWidth': 762.0, 'ShelfLength': 310.0, 'ShelfArea': 1760220.0}],
 [{'ItemNames': 2, 'ShelfWidth': 610.0, 'ShelfLength': 1220.0, 'ShelfArea': 372100.0},
  {'ItemNames': 4, 'ShelfWidth': 610.0, 'ShelfLength': 610.0, 'ShelfArea': 1450435.0}],
 [{'ItemNames': 1, 'ShelfWidth': 356.0, 'ShelfLength': 2278.0, 'ShelfArea': 759152.0}]]

有人可以建议吗?

2 个答案:

答案 0 :(得分:0)

以下是您的代码的简化版本:

data = [{'ShelfLength': 2278.0, 'ShelfWidth': 356.0, 'ShelfArea': 759152.0, 'ItemNames': 1},
    {'ShelfLength': 1220.0, 'ShelfWidth': 610.0, 'ShelfArea':   372100.0, 'ItemNames': 2},
    {'ShelfLength': 2310.0, 'ShelfWidth': 762.0, 'ShelfArea': 1760220.0, 'ItemNames': 3},
    {'ShelfLength': 610.0, 'ShelfWidth': 610.0,   'ShelfArea': 1450435.0, 'ItemNames': 4}]
SL = 'ShelfLength'
SW = 'ShelfWidth'
SA = 'ShelfArea'
IN = 'ItemNames'
max_width = 1219.2
max_len = 2438.5
max_area = 2972897.28

grouped_data = [[], []]
for record in data:
    if (record[SL] <= max_len or record[SW] <= max_width) and record[SA] <= max_area:
        grouped_data[0].append(record)
    else:
        grouped_data[1].append(record)

print(grouped_data)

这给出了相同的结果,这是正确的,因为所有元素都满足您提到的条件。

答案 1 :(得分:0)

这里的东西看似正常。由于组合中货架的顺序并不重要,它只是使用蛮力方法来检查货架的每个可能组合。因为可能要处理的数量非常多,所以编写相当高效的代码非常重要。可能有更多优化算法可以更快地实现这一点 - 本质上是一个搜索或路径查找问题。

考虑到这一点并且为了更容易地访问每个架子字典中的字段,它首先将它们全部转换为namedtuple实例的等效列表,这些实例由该点上的代码使用。 (如果你真的需要它们以字典形式存在,那么保留它的副本或在必要时重新创建它将很简单。)

转换完成后,它会检查从1到所有货架项目的所有货架项目组合。它将找到的这些内容存储在名为groups的列表中。 group[N]将包含符合条件的N项组合的子列表。 (当然,该子列表的长度是找到的那些货架数量的组合数量。)

因此,例如,在远远低于下面的输出中,它显示有4组符合条件的2个项目。 (但是,它并不打印它们的每个组合。)

from collections import namedtuple
from itertools import combinations
from operator import itemgetter

shelves_to_pack = [
    {'ShelfLength': 2278.0, 'ShelfWidth': 356.0, 'ShelfArea': 759152.0, 'ItemNames': 1},
    {'ShelfLength': 1220.0, 'ShelfWidth': 610.0, 'ShelfArea': 372100.0, 'ItemNames': 2},
    {'ShelfLength': 2310.0, 'ShelfWidth': 762.0, 'ShelfArea': 1760220.0, 'ItemNames': 3},
    {'ShelfLength': 610.0, 'ShelfWidth': 610.0, 'ShelfArea': 1450435.0, 'ItemNames': 4}]

# convert dict list into a namedtuple list to simplify field access
Shelf = namedtuple('Shelf',
                   'length width area item_names')
shelves = [Shelf(length=shelf['ShelfLength'], width=shelf['ShelfWidth'],
                 area=shelf['ShelfArea'], item_names=shelf['ItemNames'])
            for shelf in shelves_to_pack]

MAX_WIDTH, MAX_LENGTH = 1219.2, 2438.5
MAX_AREA = 2972897.28

def meets_criteria(shelf_combo):
    """ Determine if shelf combination meets criteria. """
    return (sum(shelf.area for shelf in shelf_combo) <= MAX_AREA
            and (sum(shelf.length for shelf in shelf_combo) <= MAX_LENGTH
                 or sum(shelf.width for shelf in shelf_combo) <= MAX_WIDTH))

groups = [[]]  # first group representing zero shelf items is always empty
for num_shelves in range(1, len(shelves)+1):
    groups.append([combo for combo in combinations(shelves, num_shelves)
                      if meets_criteria(combo)])
for i, group in enumerate(groups):
    print('groups of {} items: size {}'.format(i, len(group)))

这是从上面的代码和输入数据生成的输出:

groups of 0 items: size 0
groups of 1 items: size 4
groups of 2 items: size 4
groups of 3 items: size 0
groups of 4 items: size 0