我们假设我们有以下列表:
[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内置库函数可以做到这一点?或者我们是否必须为此构建手动功能?
你可以试试这个:
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)]
这是一种避免使用.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
放在正确的位置。
你也可以尝试这样的事情:
>>> 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)]
您可以通过两个简单的步骤完成此操作,让我们一步一步地探索:
第一步:
跟踪排序列表索引和值为此我们可以使用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)]
一个衬垫不使用索引并处理重复。
>>> 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)]