我有这样的数字
4, 4, 4, 7, 7, 9, 9, 9, 9, 2, 2, 2, 4, 4
我想将它们更改为
1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5
,它从1重新编号,并且以1为增量,无论是否再次出现某个数字。
那么在Python中,最有效的方法是什么?
这是我的蛋白质PDB残基ID的一系列数字。每个残基具有多个原子。 pdb还具有多个链和遗留的残基,这就是为什么输入数字在某些时候从头开始重新开始并且总是存在一些间隙的原因。但是我只希望数字从1到最后一个残差为1递增。
答案 0 :(得分:4)
使用itertools.count()
和collections.defaultdict()
object来将唯一值映射到递增的计数:
nginx:
build: webapp_nginx/.
ports:
- "80:80"
- "443:443"
volumes:
- static_data:/shared/
- ./webapp_nginx/certbot/conf:/etc/letsencrypt
- ./webapp_nginx/certbot/www:/var/www/certbot
environment:
- UWSGI_URI=172.18.0.5:29000
depends_on:
- web
certbot:
image: certbot/certbot
volumes:
- ./webapp_nginx/certbot/conf:/etc/letsencrypt
- ./webapp_nginx/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
from itertools import count
from collections import defaultdict
counter = defaultdict(count(1).__next__)
result = [counter[v] for v in inputlist]
从count(1)
开始计数(与默认起始值1
相反,每次0
时__next__
method都会产生下一个值字典查找使用的字典中尚未存在的值:
counter[v]
演示:
>>> counter = defaultdict(count(1).__next__)
>>> counter["foo"] # not yet in the dictionary
1
>>> counter["foo"] # already in the dictionary
1
>>> counter["bar"] # new value, so a new count is assigned
2
>>> counter
defaultdict(<method-wrapper '__next__' of itertools.count object at 0x10b2a7fc0>, {'foo': 1, 'bar': 2})
这确实假设,如果输入列表中的给定号码稍后再次出现(因此不在同一连续组中),则该号码会被重用:
>>> from itertools import count
>>> from collections import defaultdict
>>> example = [4, 4, 4, 7, 7, 9, 9, 9, 9, 2, 2, 2]
>>> counter = defaultdict(count(1).__next__)
>>> [counter[v] for v in example]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4]
如果这是一个问题,请使用itertools.groupby()
和enumerate()
来对连续数字组进行编号:
>>> counter_example = [4, 4, 4, 7, 7, 9, 9, 9, 9, 2, 2, 2, 4, 4, 4, 4]
>>> counter = defaultdict(count(1).__next__)
>>> [counter[v] for v in counter_example]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 1, 1, 1, 1]
此处将起始值1传递给from itertools import count, groupby
result = [c for c, (k, g) in enumerate(groupby(inputlist), 1) for _ in g]
作为第二个参数(enumerate()
与enumerate()
类似,默认情况下从count()
开始计数。
0
创建连续值相等的组,因此由其他值分隔的两次groupby()
运行形成了两个独立的组,并且每个都获得一个独立的计数。然后,您确实需要重复分配的编号,直到每个组中有多少值为止,因此最后是4
循环。
演示:
for _ in g
请注意,可以使用>>> [c for c, (k, g) in enumerate(groupby(example), 1) for _ in g]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4]
>>> [c for c, (k, g) in enumerate(groupby(counter_example), 1) for _ in g]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5]
或其他map()
函数使所有解决方案完全懒惰:
itertools
和
# lazy defaultdict lookups
counter = defaultdict(count(1).__next__)
lazy_result = map(counter.__getitem__, inputlist)
答案 1 :(得分:2)
您可以像这样使用itertools.groupby
和enumerate
>>> from itertools import groupby
>>> lst = [4, 4, 4, 7, 7, 9, 9, 9, 9, 2, 2, 2]
>>> [i for i,(_,grp) in enumerate(groupby(lst), 1) for _ in grp ]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4]