从元组列表中获取最小最大值

时间:2020-02-03 10:23:43

标签: python python-3.x list sorting tuples

我有一个元组列表,对应于某些点的(x,y)坐标(可以是8到数百个点):

mylist = [(x0,y0), (x1,y1), ..., (xn,yn)]

我想获取 x y 坐标的最小值和最大值(所有 x 的最小值,无论它们如何,等等。上)。这是为了优化比例,将点绘制到矩形区域。

所以我有两种解决方法:

  • 第一个解决方案:创建两个坐标为[foo[0] for foo in mylist]的列表,并创建一个坐标为foo[1]的列表。 然后,我可以轻松获得最小和最大。但是我必须创建列表(为了避免两次理解,一次至少一次,一次最多一次)。

  • 第二个解决方案:对列表进行两次排序,一次是根据第一个坐标,然后是第二个坐标,每次都获得第一个和最后一个值。内存使用较少,但需要排序。

什么是最佳解决方案?

5 个答案:

答案 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)]

截至本次编辑(2月4日12:28 AM)在python 3.7和Windows 10中的

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)

您可以将maxitemgetter()函数一起使用,与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。在这里,您可以通过以下步骤进一步优化您的方法

  • 步骤1:解析整个列表一次,以获得x_min和y_min。复杂度为O(N)
  • 步骤2:仅存储具有x_min和y_min的元组的索引(节省了50%以上的空间)。复杂度为O(N)。

如果您只想查找最小值或最大值,请不要对如此大的列表进行排序。排序可以从O(N * N)到O(NlogN)进行。