2015-07-09 35 views
2

開始比方說,我有一個這樣的名單:替換具有獨特的項目列表中的項目從0

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

什麼是最Python的方式與

  • 最低未使用的整數來替代每個號碼(> = 0),如果該號碼之前尚未
  • 看出,已被用來取代數否則
相同的整數

以便列表變爲:

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

這不是重要的是,第一個元素是0,但必須有數字的兩個列表之間的唯一最大匹配(=分配),即還,這是一個很好的解決方案:

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

編輯:我試過是一些使用find循環,我的解決方案是非常難看的,我知道有更好的方式來做到這一點,它不是有關我多麼糟糕做到了:d

+0

既然SO不是代碼編寫服務,如果你想得到一個正確的答案,你需要添加你迄今試過的代碼! – Kasramvd

+2

你是否還希望'1018'出現在同一個整數中,如果它出現在列表的後面? '[1018,1011,1018]'應該是'[0,1,0]還是'[0,1,2]'? –

+1

@AdamSmith是的,[0,1,0]是正確的(它就像條款的替代) – pawawa

回答

4

首先想到的想法是將值轉換爲set()enumerate()他們存儲在一個字典的對,並使用映射列表解析來創建新的列表:

>>> 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] 
+0

感謝這比我想象中的任何東西都短得多和優雅! – pawawa

5

你也可以使用一個defaultdictitertools.count,如:

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] 

如何這項工作是一個defaultdict將返回現有密鑰的值,但如果該密鑰不存在,它會將該密鑰分配給默認值 - 在這種情況下,該值是按順序排列的下一個數字。

+0

哦,這很有趣!我喜歡。 –

+0

我不明白這一個。爲什麼它會在第二次返回0? – pawawa

+0

我認爲如果你將c聲明爲局部變量,那麼邏輯就會更清晰,而不是(ab)使用python默認變量作用域。儘管如此,非常酷。 –

1

這是我通常使用的。核心邏輯與@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())