简体   繁体   English

使用从0开始的唯一项替换列表中的项

[英]Replace items in a list with unique items starting from 0

Let's say I have a list like this: 假设我有一个这样的列表:

Y=[1018, 1018, 1011, 1012, 1013, 1014, 1019, 1019, 1017]

What's the most pythonic way to replace each number with 更换每个数字的最佳方式是什么?

  • the lowest unused integer (>=0), if the number has not been seen before 如果之前没有看到过这个数字,那么最低的未使用整数(> = 0)
  • the same integer that has been used to replace the number otherwise 否则用于替换数字的相同整数

So that the list becomes: 这样列表变成:

Y=[0, 0, 1, 2, 3, 4, 5, 5, 6]

It's not important that first element is 0, but there must be a unique maximal matching (= assignment) between the two lists of numbers, ie also this is a good solution: 第一个元素为0并不重要,但两个数字列表之间必须存在唯一的最大匹配(=赋值),即这也是一个很好的解决方案:

Y=[3, 3, 4, 0, 2, 5, 6, 6, 1]

EDIT: what I tried is a for loop using find, my solution is very ugly, I know there is better way to do it, it's not relevant how bad I did it :D 编辑:我尝试的是使用find的for循环,我的解决方案非常难看,我知道有更好的方法来做到这一点,这与我做得有多糟糕无关:D

The first idea that comes to mind is to convert the values to a set() and enumerate() them, store the pairs in a dict, and use a mapping list comprehension to create the new list: 想到的第一个想法是将值转换为set()enumerate()它们,将对存储在dict中,并使用映射列表理解来创建新列表:

>>> Y=[1018, 1018, 1011, 1012, 1013, 1014, 1019, 1019, 1017]
>>> mapping={v:k for k,v in enumerate(set(Y))}
>>> Y1=[mapping[y] for y in Y]
>>> Y1
[5, 5, 0, 1, 2, 3, 6, 6, 4]

You can also use a defaultdict with itertools.count , eg: 您还可以在itertools.count使用defaultdict ,例如:

from collections import defaultdict
from itertools import count

dd = defaultdict(lambda c=count(): next(c))

Y=[1018, 1018, 1011, 1012, 1013, 1014, 1019, 1019, 1017]
mapped = [dd[el] for el in Y]
# [0, 0, 1, 2, 3, 4, 5, 5, 6]

How this works is that a defaultdict will return the value for an existing key but where that key doesn't exist, it will assign the key to a default value - in this case that value is the next number in sequence. 这是如何工作的, defaultdict将返回现有键的值,但该键不存在的位置,它将键分配给默认值 - 在这种情况下,该值是序列中的下一个数字。

Here's what I typically use. 这是我通常使用的。 The core logic is basically the same as what @JonClements wrote. 核心逻辑与@JonClements编写的内容基本相同。

#!/usr/bin/env python3

# mypy static typing annotations
from typing import Dict, Generic, List, TypeVar

T = TypeVar('T')

class Interner(Generic[T]):
    def __init__(self):
        self._values = [] # type: List[T]
        self._keys = {} # type: Dict[T, int]
    def intern(self, val: T) -> int:
        idx = self._keys.setdefault(val, len(self._keys))
        if idx == len(self._values):
            self._values.append(val)
        return idx
    def unintern(self, idx: int) -> T:
        return self._values[idx]
    pass

def main():
    data = [1018, 1018, 1011, 1012, 1013, 1014, 1019, 1019, 1017]
    pool = Interner() # type: Interner[int]
    return [pool.intern(i) for i in data]

if __name__ == '__main__':
    print(main())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM