我正在尝试为小数knapsack problem编写不同的实现。
为此,我有2个阵列:
元素值[n]对应于元素权重[n]。所以我们可以将value_per_unit计算为:
for I in range(values):
value_per_unit.append(values[I]/weights[I])
value_per_unit.sort()
我现在需要根据value_per_unit数组排序2个数组(值和权重)
例如: 如果
然后
values_per_unit = [3.0,2.0,4.0]
所以values_per_unit_sorted将是[2.0,3.0,4.0]
我需要将值和权重数组变为:
有没有办法使用简单的lambda函数来实现这个目的?
我仍然可以做这样的事情,但是每次我需要访问元素时效率都非常低:
weights[(value_per_unit_sorted.index(max(value_per_unit_sorted)))]
答案 0 :(得分:6)
在一行中:
values, weights = zip(*sorted(zip(values, weights), key=lambda t: t[0]/t[1]))
解释:首先,压缩列表以配对它们。
pairs = zip(values, weights)
# [(60, 20), (100, 50), (120, 30)]
然后,按值与重量的商进行排序。
sorted_pairs = sorted(pairs, key=lambda t: t[0]/t[1])
# [(100, 50), (60, 20), (120, 30)]
最后,将它们解压缩回单独的列表中。
values, weights = zip(*sorted_pairs)
# (100, 60, 120), (50, 20, 30)
另一种方法是构造明确包含比率作为第一个元素的元组。
ratios, values, weights = zip(*sorted((v/w, v, w) for v, w in zip(values, weights)))
前者在某些快速测试中似乎稍快一些。如果您正在寻找最佳算法,那么您可能需要展开一些内容,而且解决方案也不会那么简洁。
要解决@TomWyllie的评论,如果你已经有比率列表,你可以使用:
ratios, values, weights = zip(*sorted(zip(ratios, values, weights)))
注意,在两对具有相等比率的情况下,最后两个解决方案与初始解决方案不同。这些解决方案将按值排序,而第一个解决方案将使项目保持与原始列表相同的顺序。
答案 1 :(得分:0)
对于更明确(但可以说更少pythonic)的解决方案,创建一个索引列表,按 value_per_unit
中该索引处的值排序,并重新排序values
和weights
因此。{/ p>
sorted_indices = [index for index, value in
sorted(enumerate(value_per_unit), key=lambda x: x[1])]
values = [values[i] for i in sorted_indices]
weights = [weights[i] for i in sorted_indices]
print(values, weights)
输出:
([100, 60, 120], [50, 20, 30])
你可以整理一下,使用zip
消除不必要的额外循环,并使用生成器表达式;
values, weights = zip(*((values[i], weights[i]) for i, value in
sorted(enumerate(value_per_unit), key=lambda x: x[1])))
print(values)
print(weights)
哪些输出;
(100, 60, 120)
(50, 20, 30)
请注意,这些最终值为tuples
而不是lists
。如果您确实需要将输出作为列表,那么简单的values, weights = map(list, (values, weights))
就足够了。你甚至可以把它包装成一个班轮,虽然到那时它可能很难跟上发生的事情。
答案 2 :(得分:0)
执行此操作的一种优雅方法是使用值和权重创建多维列表:
for i in range(len(values)):
values_and_weights.append([values[i], weights[i])
# The resulting list is [[60, 20], [100, 50], [120, 30]]
然后,使用以权重除以权重的排序方法作为关键字。
values_and_weights.sort(key=(lambda x: x[0]/x[1]))
答案 3 :(得分:-1)
您遇到的问题是在每个元素上使用计算字段(元素I将具有计算值values[I]/weights[I]
)。
要解决这个问题并且仍然非常容易理解,您可以将其转换为这种形式的元组:( calculated_value, (value, weight) )
,每个元素。
这种方法使其易于阅读和理解。请看以下解决方案:
values = [60, 100, 120]
weights = [20, 50, 30]
value_per_unit = []
for I in range(len(values)):
value_per_unit.append( (values[I]/weights[I], (values[I], weights[I])) )
sorted_value_per_unit = sorted(value_per_unit, key=lambda x: x[0])
sorted_values = []
sorted_weights = []
for I in range(len(values)):
(value, weight) = sorted_value_per_unit[I][1]
sorted_values.append(value)
sorted_weights.append(weight)
print(str(sorted_values))
print(str(sorted_weights))
另外,请注意我从原始代码修改了循环:
range(values)
已更改为range(len(values))
因为范围需要列表的长度,而不是列表本身。