Python:按照升序x数组排序y值数组

9
如果我有两个这样的数组:
x = [0, 7, 2, 4, 6, 9, 5]

y = [1, 2, 3, 4, 5, 6, 7]

即,我有数据点在[0,1][3,2][x_n,y_n]等位置。如何为相应的升序x值组织y?换句话说,我最终得到x的升序值:

x = [0, 2, 4, 5, 6, 7, 9]

与其对应的y值匹配:

y = [1, 3, 4, 7, 5, 2, 6]

我猜需要将这两个数组拼接在一起,然后按照x排序,但是具体的语法我不太确定。非常感谢任何帮助。

4个回答

6

我会使用ziplambda

In [55]: x = [0, 7, 2, 4, 6, 9, 5]

In [56]: y = [1, 2, 3, 4, 5, 6, 7]

In [57]: L = sorted(zip(x,y), key=operator.itemgetter(0))

In [58]: new_x, new_y = zip(*L)

In [59]: new_x
Out[59]: (0, 2, 4, 5, 6, 7, 9)

In [60]: new_y
Out[60]: (1, 3, 4, 7, 5, 2, 6)

别忘了导入 operator


1
除非你特别不想在绑定的情况下按第二个元素排序,否则不需要指定按第一个元素排序。此外,你的代码中没有使用lambda函数。 - Cyphase
我这样做是因为它似乎符合 OP 的要求。但是我猜不给 sorted 一个 key 可能会稍微提高运行效率。 - inspectorG4dget
1
当然,它是适合的;OP没有明确表示是否需要/应该打破平局。我只是想提一下:)。 - Cyphase
@Cyphase:明确规范是个好主意。顺便说一下:我真的不确定 OP 想用这个做什么。我猜想是某种最近点对分治应用? - inspectorG4dget
老兄!这个答案太棒了! - hargun3045

4
你可以在将它们 zip(压缩)之后,将其排序为元组。
>>> sorted((i,j) for i,j in zip(x,y))
[(0, 1), (2, 3), (4, 4), (5, 7), (6, 5), (7, 2), (9, 6)]

为了遍历这些键值对,你可以像这样做:
sorted_pairs = sorted((i,j) for i,j in zip(x,y))
for i,j in sorted_pairs:
    # do something with each i and j value, which are x and y respectively

或者你可以直接索引,如下所示:

sorted_pairs[0][0]  # x of the first tuple
sorted_pairs[0][1]  # y of the first tuple
sorted_pairs[3][0]  # x of the fourth tuple... etc

我现在要如何引用 i 的值呢?x[i]? - GCien
1
或者执行new_x, new_y = zip(*sorted_pairs)。但如果这些是单个数据点,那么将它们放入一个元组列表中是有意义的。你可以使用namedtuple使访问更方便。或者如果你只需要遍历它们,可以使用答案中的for循环,并使用更合适的变量名(我们不知道这些东西是什么,所以无法给它们取好的名称)。 - Cyphase
2
甚至可以使用zip(*sorted(zip(x,y))) - wwii
@wwii,哦,是的,忘了提到那个:P。对于任何不理解的人,((i, j) for i, j in zip(x, y))返回的东西与zip(x, y)相同,因此您应该直接使用zip(x, y)。 @wwii答案中的外部zip仅在您再次拆分列表时才需要;否则,请执行sorted_pairs = sorted(zip(x, y)) - Cyphase
如果您需要索引值,请使用 enumerate。@Michael Roberts - saulspatz
@saulspatz,那应该放在问题上。话虽如此,OP并不想要索引;他想要按其中一个元素对这些对进行排序。 - Cyphase

0

嘿,我写了这个函数:

def sort_bar(bar_list):
    sorted_x = []
    sorted_x.extend(bar_list['x'])
    sorted_x.sort()
    sorted_y = []
    for x in sorted_x:
        sorted_y.append(bar_list['y'][bar_list['x'].index(x)])
    return {"x": sorted_x, "y": sorted_y}

例子:

unsorted = {
    "x": [5, 9, 2, 3],
    "y": [8, 6, 3, 4]
}
sorted = sort_bar(unsorted)

0

我喜欢其他的例子(从中学到了一些东西)。我的答案有点不同:首先将x项转换为(索引,x [index])元组,根据元组中的第2项对这样的列表进行排序,获取索引作为列表,并使用索引列表从y列表中选择值。

如果有更多像y这样的列表需要按照x列表中的项目顺序进行排序,则此方法可能变得高效。

简化版本

>>> x = [0, 7, 2, 4, 6, 9, 5]
>>> y = [1, 2, 3, 4, 5, 6, 7]
>>> from operator import itemgetter
>>> pick_0 = itemgetter(0)
>>> pick_1 = itemgetter(1)
>>> x_decor = sorted(enumerate(x), key=pick_1)
>>> x_idxs = map(pick_0, x_decor)
>>> multi_picker = itemgetter(*x_idxs)
>>> multi_picker(y)
(1, 3, 4, 7, 5, 2, 6)

让我解释一下,它是如何工作的以及为什么在某些情况下可能很相关。

装饰、排序、获取索引、使用它们来选择结果项

首先,获取要处理的值:

>>> x = [0, 7, 2, 4, 6, 9, 5]
>>> y = [1, 2, 3, 4, 5, 6, 7]

然后使用enumerate将值与列表x中的项目索引装饰:

>>> x_decor = [(idx, val) for idx, val in enumerate(x)]
>>> x_decor
[(0, 0), (1, 7), (2, 2), (3, 4), (4, 6), (5, 9), (6, 5)]

根据值(现在是 itm[1],因为 itm[0] 是原始位置索引)对装饰列表进行排序:
>>> x_decor.sort(key=lambda itm: itm[1])
>>> x_decor
[(0, 0), (2, 2), (3, 4), (6, 5), (4, 6), (1, 7), (5, 9)]

最后得到与排序后的x相关的位置索引列表:

>>> x_idxs = [idx for idx, val in x_decor]
>>> x_idxs
[0, 2, 3, 6, 4, 1, 5]

现在我们使用x_idxsy列表中选择相关项:

>>> y_vals = [y[idx] for idx in x_idxs]
>>> y_vals
[1, 3, 4, 7, 5, 2, 6]

如果我们有其他列表(如果有的话),则可以重复执行此最后一步。

使用itemgetter进行优化版本

可以使用itemgetter来优化以提高速度。

itemgetter能够创建一个函数,允许从特定位置选择值。 itemgetter还可以创建函数,允许一次从预定义位置选择多个值。

>>> from operator import itemgetter
>>> itemgetter(0)
<operator.itemgetter at 0x7f8e300afd90>
>>> pick_0 = itemgetter(0)
>>> pick_1 = itemgetter(1)
>>> pick_0_2 = itemgetter(0, 2)

让我们看看这些函数能为我们做什么:

>>> pick_0(["a", "b", "c"])
'a'
>>> pick_1(["a", "b", "c"])
'b'
>>> pick_0_2(["a", "b", "c"])
('a', 'c')

让我们像以前一样创建装饰的x,这次使用稍微简短的语法:

>>> x_decor = sorted(enumerate(x), key=pick_1)
>>> x_decor
[(0, 0), (2, 2), (3, 4), (6, 5), (4, 6), (1, 7), (5, 9)]

enumerate(x) 创建了装饰列表,sorted 使用 key=pick_1 根据原始列表 x 的值进行排序。

使用 pick_0,我们可以仅获取装饰列表中的索引列表:

>>> x_idxs = map(pick_0, x_decor)
>>> x_idxs
[0, 2, 3, 6, 4, 1, 5]

这些索引可以用来创建 multi_picker(类似于上面的 pick_0_2):

>>> multi_picker = itemgetter(*x_idxs)
>>> multi_picker
<operator.itemgetter at 0x7f8e300afb10>

使用multi_picker从列表y中获取正确排序的元素:

>>> y_vals = multi_picker(y)
>>> y_vals
(1, 3, 4, 7, 5, 2, 6)

如果我们有更多的列表需要根据已排序的x元素进行排序,那么现在只需要调用multi_picker函数即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接