我有一个元组列表,对应于某些点的(x,y)坐标(可以是8到数百个点):
mylist = [(x0,y0), (x1,y1), ..., (xn,yn)]
我想获取 x 和 y 坐标的最小值和最大值(所有 x 的最小值,无论它们如何,等等。上)。这是为了优化比例,将点绘制到矩形区域。
所以我有两种解决方法:
第一个解决方案:创建两个坐标为[foo[0] for foo in mylist]
的列表,并创建一个坐标为foo[1]
的列表。
然后,我可以轻松获得最小和最大。但是我必须创建列表(为了避免两次理解,一次至少一次,一次最多一次)。
第二个解决方案:对列表进行两次排序,一次是根据第一个坐标,然后是第二个坐标,每次都获得第一个和最后一个值。内存使用较少,但需要排序。
什么是最佳解决方案?
答案 0 :(得分:5)
您可以在此处使用zip
。
In [1]: a=[(1,2),(3,4),(5,6)]
In [2]: x,y=zip(*a)
In [3]: x
Out[3]: (1, 3, 5)
In [4]: y
Out[4]: (2, 4, 6)
In [5]: min(x),max(x)
Out[5]: (1, 5) #1 in min and 5 is max in x
In [6]: min(y),max(y)
Out[6]: (2, 6) #2 is min and 5 is max in y
timeit
上的google colab
分析。
%timeit minmax(z) #ch3ster's answer
1 loop, best of 3: 546 ms per loop
%timeit minmax1(z) #CDJB's answer
1 loop, best of 3: 1.22 s per loop
%timeit minmax2(z) #Mihai Alexandru-Ionut's answer
1 loop, best of 3: 749 ms per loop
%timeit minmax3(z) #Yevhen Kuzmovych's answer
1 loop, best of 3: 1.59 s per loop
编辑:如果在此处使用set
,我们仍然可以减少执行时间。
In [24]: def minmax(a):
...: x=set()
...: y=set()
...: for i,j in a:
...: x.add(i)
...: y.add(j)
...: return max(x),min(x),max(y),min(y)
使用元组列表(大小为300万或300万)进行基准测试。
z=[(randint(0,10),randint(0,10)) for _ in range(3000000)]
timeit
分析。
In [25]: timeit minmax(z) #Ch3steR's set answer.
384 ms ± 26.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [44]: timeit minmax1(z) #Ch3steR's zip answer.
626 ms ± 3.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [39]: timeit minmax2(z) #CDJB's answer max with lambda
1.18 s ± 25.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [40]: timeit minmax3(z) #Mihai Alexandru-Ionut's answer max with itemgetter
739 ms ± 42.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [41]: timeit minmax4(z) #Yevhen Kuzmovych's answer with updating max and min while iterating
1.97 s ± 42.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Ch3steR的设置答案
0<= x,y <=1000000
时
用于基准测试的列表。
x=[(randint(0,1000000),randint(0,1000000)) for _ in range(3000000)]
timeit
分析。
In [48]: timeit minmax(x) #Ch3steR's set answer.
1.75 s ± 92.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [49]: timeit minmax1(x) #Ch3steR's zip answer.
753 ms ± 31.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [51]: timeit minmax2(x) #CDJB's answer max with lambda
1.29 s ± 115 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [52]: timeit minmax3(x) #Mihai Alexandru-Ionut's answer max with itemgetter
794 ms ± 35.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [53]: timeit minmax4(x) #Yevhen Kuzmovych's answer with updating max and min while iterating
2.3 s ± 164 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
注意:
Ch3steR的设置在0< x,y < 10
时很有效,但是在0< x,y <1000000
时平均为1.7s
我强烈建议在0< x,y < 1000000
时将 Ch3steR的答案与zip 或 Mihai Alexandru-Ionut的答案的最大值和最小值与itemgetter 一起使用。
答案 1 :(得分:5)
您可以将max
与itemgetter()
函数一起使用,与more
相比,我认为它是lambda
有效的 solution ,符合{{3} }。
from operator import itemgetter
max_x = max(mylist,key=itemgetter(0))[0]
答案 2 :(得分:2)
这是另一种解决方案:
max_x, max_y = min_x, min_y = mylist[0]
for x, y in mylist:
max_x = max(max_x, x)
max_y = max(max_y, y)
min_x = min(min_x, x)
min_y = min(min_y, y)
答案 3 :(得分:1)
您可以将min()
和max()
与key
参数一起使用。要获得所需的结果,您可以使用:
max_y = max(mylist, key=lambda x: x[1])[1]
min_y = min(mylist, key=lambda x: x[1])[1]
max_x = max(mylist, key=lambda x: x[0])[0]
min_x = min(mylist, key=lambda x: x[0])[0]
答案 4 :(得分:1)
欢迎您!
希望这对您有所帮助。
我建议您参加option1
。在这里,您可以通过以下步骤进一步优化您的方法
如果您只想查找最小值或最大值,请不要对如此大的列表进行排序。排序可以从O(N * N)到O(NlogN)进行。