在python的列表中创建一对order,value的值

问题描述 投票:-1回答:5

我们假设我们有以下列表:

[3, -1, 2, 100, 5]

(这只是一个例子,可以是任何包含任意长度实数的列表)

如果我们排序,我们得到

[-1, 2, 3, 5, 100]

意思是-1是最小的,2是第2小,3是第3小,5是第4小,100是最大,所以如果-1是1阶统计,2是2阶统计,3是3阶统计,5是4阶统计量,100是5阶统计量。现在,回到原始列表,我想要更改原始列表

[3, -1, 2, 100, 5]

[(3, 3), (-1, 1), (2, 2), (100, 5), (5, 4)]

一对(值,其顺序)的列表

是否有python内置库函数可以做到这一点?或者我们是否必须为此构建手动功能?

python algorithm
5个回答
4
投票

你可以试试这个:

s = [3, -1, 2, 100, 5]
new_s = sorted(s)
final_s = [(i, new_s.index(i)+1) for i in s]

输出:

[(3, 3), (-1, 1), (2, 2), (100, 5), (5, 4)]

如果s不是唯一的:

s = [3, 3, 3, 2, 100, -1, 100, 5]
new_s = sorted(s)
final_s = [(a, [i for i, b in enumerate(new_s) if b == a]) for a in s]
last_s = [(a, list(map(lambda x:x+1, b)) if len(b) > 1 else b[0]) for a, b in final_s]

输出:

[(3, [3, 4, 5]), (3, [3, 4, 5]), (3, [3, 4, 5]), (2, 1), (100, [7, 8]), (-1, 0), (100, [7, 8]), (5, 5)]

4
投票

这是一种避免使用.index的方法。 .index方法存在两个问题。首先,它相对较慢,因为它必须对列表项执行线性扫描,直到找到匹配项。其次,它总是在找到第一个匹配项时停止,因此如果原始列表中存在重复项,则将其用于此任务会出现问题。解决这个问题的一种方法是使用enumerate两次。

这是一个稍微复杂的操作,所以我将分阶段进行。

a = [3, -1, 2, 100, 5]
print(a)

b = sorted((u, i) for i, u in enumerate(a))
print(b)

c = sorted((i, u, j) for j, (u, i) in enumerate(b, 1))
print(c)

d = [u[1:] for u in c]
print(d)

产量

[3, -1, 2, 100, 5]
[(-1, 1), (2, 2), (3, 0), (5, 4), (100, 3)]
[(0, 3, 3), (1, -1, 1), (2, 2, 2), (3, 100, 5), (4, 5, 4)]
[(3, 3), (-1, 1), (2, 2), (100, 5), (5, 4)]

将这3个阶段组合成一个单独的陈述是可能的,但结果是几乎不可读的怪物。 ;)

d = [u[1:] for u in sorted((i, u, j) for j, (u, i) in
    enumerate(sorted((u, i) for i, u in enumerate(a)), 1))]

FWIW,这项技术是Schwartzian transform的变种。


这是一个包含重复项目的列表的测试,该项目将我的算法与使用.index的算法进行比较。

a = [3, -1, 2, 100, -1, 5]
print(a)

lst = a
sorted_list = [(e, i+1) for i,e in enumerate(sorted(lst))]
result = sorted(sorted_list, key = lambda x : lst.index(x[0]))
print(result)

b = sorted((u, i) for i, u in enumerate(a))
c = sorted((i, u, j) for j, (u, i) in enumerate(b, 1))
d = [u[1:] for u in c]
print(d)

产量

[3, -1, 2, 100, -1, 5]
[(3, 4), (-1, 1), (-1, 2), (2, 3), (100, 6), (5, 5)]
[(3, 4), (-1, 1), (2, 3), (100, 6), (-1, 2), (5, 5)]

如你所见,我的版本将第二个-1放在正确的位置。


3
投票

你也可以尝试这样的事情:

>>> lst = [3, -1, 2, 100, 5]
>>> sorted_list = [(e, i+1) for i,e in enumerate(sorted(lst))]
>>> print(sorted_list)
[(-1, 1), (2, 2), (3, 3), (5, 4), (100, 5)]
>>> result = sorted(sorted_list, key = lambda x : lst.index(x[0]))
>>> print(result)
[(3, 3), (-1, 1), (2, 2), (100, 5), (5, 4)]

如果列表中有重复项,则需要更改方法。一种方法是通过(number, [counts])对字典中的相似值进行分组,并且一旦从pop()读取原始值,lst就会一次关闭它们:

from collections import defaultdict

lst = [3, -1, 2, 3, 5, 2, 100, 5]

sorted_list = [(e, i+1) for i,e in enumerate(sorted(lst))]

d = defaultdict(list)
for number, count in sorted_list:
    d[number].append(count)

result = [(number, d[number].pop(0)) for number in lst]

print(result)

哪个输出:

[(3, 4), (-1, 1), (2, 2), (3, 5), (5, 6), (2, 3), (100, 8), (5, 7)]

1
投票

您可以通过两个简单的步骤完成此操作,让我们一步一步地探索:

第一步:

跟踪排序列表索引和值为此我们可以使用dict:

track={}
data_1=[3, -1, 2, 100, 5]
for i,j in enumerate(sorted(data_1),1):
    track[j]=i

这会给:

{2: 2, 3: 3, 100: 5, 5: 4, -1: 1}

第二步

只是迭代原始数据并从track dict中获取该项的键:

print([(item,track.get(item)) for item in data_1])

输出:

[(3, 3), (-1, 1), (2, 2), (100, 5), (5, 4)]

1
投票

一个衬垫不使用索引并处理重复。

>>> s = [3, -1, 2, 100, 5]
>>> list((x[1][1], x[0]) for x in sorted(enumerate(sorted(enumerate(s), key=lambda x: x[1]), 1), key=lambda x: x[1][0]))
[(3, 3), (-1, 1), (2, 2), (100, 5), (5, 4)]
© www.soinside.com 2019 - 2024. All rights reserved.