我正在编写一段代码,并且必须对给定的列表进行排序。
prices = [5, 11, 3, 50, 60, 90]
k = 2
all_posible_sales = []
i=0
for buy in prices[i:len(prices)]:
for sell in prices[i:len(prices)]:
a = tuple((buy, sell))
all_posible_sales.append(a)
i += 1
for data in all_posible_sales:
if data[1] - data[0] < 0 or data[1] - data[0] == 0:
all_posible_sales.remove(data)
print(all_posible_sales)
这段代码连接了所有可能的销售(两个嵌套的for
循环),并删除了差为负值的变量(最终的for
循环)。
当我检查输出时,我发现一件非常令人不愉快的事情:元组(11, 3)
在那里,它一定不在那里,这符合我的逻辑。
data1 -数据<0\3-11<0(真)
这个价值有什么问题,我做错什么了吗?
发布于 2021-02-11 23:02:18
与将元素添加到列表中然后删除不同,您只需将有效元素添加到列表中,方法如下:
prices = [5, 11, 3, 50, 60, 90]
k = 2
all_posible_sales = []
i=0
for buy in prices[i:len(prices)]:
for sell in prices[i:len(prices)]:
if sell - buy > 0:
a = tuple((buy, sell))
all_posible_sales.append(a)
还请阅读此一,以了解如何为未来的应用程序成功地从列表中删除项。
发布于 2021-02-12 01:49:58
引言
这两个发布的答案实际上都没有解决代码中的问题。问题是,您没有从正在迭代转发的列表中删除项。要开始了解原因,请打印实际被删除的元组:
(5, 5)
(5, 3)
(11, 11)
(3, 3)
(50, 50)
(60, 60)
(90, 90)
注意,(11, 3)
从未被检查过。这是因为列表迭代器基于索引工作。每次移除项时,以下所有项都会移回一个项,但是迭代器会继续递增。下面是起始all_possible_sales
列表中的一个示例:
5 <= 5
。注意数据向后移动,但是迭代器保持在列表中相同的位置:[(5,11),(5,3),(5,50),.^ i=0希望您能够看到如何跳过(5, 11)
,以及之后的许多元素(实际上,几乎每一个其他元素)。
解决方案
现在让我们来看看一些解决方案。我从一些几乎是表面上的改变开始,工作到彻底修改您的代码,甚至比其他答案所推荐的更多。
反向迭代
当您向后迭代一个列表时,删除不会影响您没有遍历的索引。列表有一个反向迭代器,这意味着调用reversed
不会复制任何东西,因此时间和内存都很便宜。
因此,最简单的解决方案是将第二个循环替换为:
for data in reversed(all_posible_sales):
复制输入
如果创建输入列表的副本,其元素将指向相同的对象,但从原始列表中删除项不会影响迭代器对副本的影响。这比颠倒原始列表要昂贵得多,因为它实际上分配了第二个列表。
该解决方案至少可以用三种不同的方式编写:
for data in list(all_posible_sales):
for data in all_posible_sales.copy():
for data in all_posible_sales[:]:
不包括不必要的元素
正如其他答案所示,最好的方法是排除不属于的元素,而不是稍后删除它们。这种方法的部分答案是调整循环,这样就不会创建表单(buy, buy)
的元组
for ibuy in range(len(prices) - 1):
buy = prices[ibuy]
for isell in range(ibuy + 1, len(prices)):
sell = prices[isell]
条件内循环
从列表中排除项目的最简单方法是,从一开始就不包括它们:
for ibuy in range(len(prices) - 1):
buy = prices[ibuy]
for isell in range(ibuy + 1, len(prices)):
sell = prices[isell]
if buy < sell:
all_posible_sales.append((buy, sell))
print(all_posible_sales)
清单理解
任何嵌套的for
循环,只要有条件和列表append
,都可以作为列表理解来更有效地(如果不是更清楚地)编写。在这种情况下,它将涉及更多的索引:
all_posible_sales = [(prices[ibuy], prices[isell]) for ibuy in range(len(prices) - 1) for isell in range(ibuy + 1, len(prices)) if prices[ibuy] < prices[isell]]
请注意,这就像按照与以前完全相同的顺序编写循环和条件,但都在一行上,没有冒号。唯一的区别是append
调用的内容在开头。
Numpy
像这样有数字的东西非常适合于矮胖。如果您正在进行任何类型的数字处理,那么您几乎不可避免地会导入numpy
、scipy
或pandas
的一部分。您的代码将更干净和更快。
如果将prices
转换为numpy数组,则可以在循环结束时使用函数np.triu_indices
查找相同的对。然后,您可以将所选内容连接到一个买卖价格的Nx2数组中:
import numpy as np
prices = np.array(prices)
ibuy, isell = np.triu_indices(len(prices), k=1)
all_possible_sales = np.stack((prices[ibuy], prices[isell]), axis=-1)[prices[ibuy] < prices[isell]]
备注
len(prices)
:prices[i:]
将接受所有元素到末尾,而prices[i:-1]
将接受所有元素,直到结束时有一个元素,等等。data[1] - data[0] < 0 or data[1] - data[0] == 0
可以以data[1] - data[0] <= 0
的形式编写得简洁得多。更好的(我认为,更直截了当地说)是比较data[1] <= data[0]
。tuple((buy, sell))
完全等同于(buy, sell)
。我觉得后者读起来不那么令人困惑。for sell in prices[i:len(prices)]:
在外部循环的每次迭代中生成一个prices
片段的完整副本。迭代range
对象并将其索引到prices
中可能要便宜得多。发布于 2021-02-11 23:00:39
在迭代列表时,不要从列表中删除,除非您知道自己在做什么。使用列表理解代替:
all_posible_sales = [s for s in all_posible_sales if s[0] < s[1]]
print(all_posible_sales)
# [(5, 11), (5, 50), (5, 60), (5, 90), (11, 50), (11, 60), (11, 90), (3, 50), (3, 60), (3, 90), (50, 60), (50, 90), (60, 90)]
https://stackoverflow.com/questions/66164174
复制相似问题