我正在编写一段代码,并且必须对给定的列表进行排序。
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
复制相似问题