2012-07-15 63 views
1

這裏是一個輸入列表索引:如何保持重複元素的不變

['a', 'b', 'b', 'c', 'c', 'd'] 

我預計應該是輸出:

[[0, 'a'], [1, 'b'], [1, 'b'], [2, 'c'], [2, 'c'], [3, 'd']] 

我嘗試使用地圖()

>>> map(lambda (index, word): [index, word], enumerate([['a', 'b', 'b', 'c', 'c', 'd']]) 
[[0, 'a'], [1, 'b'], [2, 'b'], [3, 'c'], [4, 'c'], [5, 'd']] 

我怎樣才能得到預期的結果?

編輯:這不是一個排序列表,每個元素的索引像你想排名根據字典序條件滿足時,一個新的元素

+2

是按姓名排序? – 2012-07-15 08:11:47

+0

非常感謝,我忘了這個關鍵點 – fishiwhj 2012-07-15 08:22:42

回答

1

聽起來只會增加。

input = ['a', 'b', 'b', 'c', 'c', 'd'] 
mapping = { v:i for (i, v) in enumerate(sorted(set(input))) } 
[ [mapping[v], v] for v in input ] 

請注意,這也適用於未排序的輸入。

如果根據您的修改建議,您希望根據第一次出現的順序對項目編號,則需要採用不同的方法。以下是簡短而親切,雖然進攻哈克:

[ [d.setdefault(v, len(d)), v] for d in [{}] for v in input ] 
+0

不錯的解決方案,但太長的名單工作太多; O(n * log(n)),但明顯的解決方案需要O(n) – 2012-07-15 08:17:32

+0

@IgorChubin:假設排序後的輸入只能做得更好。我故意避免這種情況。 – 2012-07-15 08:18:53

+0

無需排序輸入。 O(n)解決方案是顯而易見的,你完全需要排序輸入。 – 2012-07-15 08:21:59

6
>>> import itertools 
>>> seq = ['a', 'b', 'b', 'c', 'c', 'd'] 
>>> [[i, c] for i, (k, g) in enumerate(itertools.groupby(seq)) for c in g] 
[[0, 'a'], [1, 'b'], [1, 'b'], [2, 'c'], [2, 'c'], [3, 'd']] 
+0

+1,但是不要忘記在 – 2012-07-15 08:12:19

+0

之前對列表進行排序@IgorChubin取決於OP的要求,他沒有針對未排序列表的結果,所以我不確定。 .. – jamylak 2012-07-15 08:14:14

+0

哇,你快! – 2012-07-15 08:15:49

1

當列表排序使用groupby(見jamylak答案);如果沒有,只需重複列表並檢查是否已經看到此字母:

a = ['a', 'b', 'b', 'c', 'c', 'd'] 
result = [] 
d = {} 
n = 0 
for k in a: 
    if k not in d: 
    d[k] = n 
    n += 1 
    result.append([d[k],k]) 

這是最有效的解決方案;它只需要O(n)的時間。

使用率無序列表的例子:

[[0, 'a'], [1, 'b'], [1, 'b'], [2, 'c'], [2, 'c'], [3, 'd'], [0, 'a']] 

正如你所看到的,你在這裏的項目相同的順序輸入列表中。

當您首先對列表進行排序時,您需要O(n * log(n))附加時間。

4
[ 
    [i, x] 
    for i, (value, group) in enumerate(itertools.groupby(['a', 'b', 'b', 'c', 'c', 'd'])) 
    for x in group 
] 
+0

與jamylak的解決方案相同;僅適用於已排序的列表。 – 2012-07-15 08:19:09

+0

真的完全一樣,只是不同的名稱和OP中的內聯值。並想出了稍微慢一點:) – 2012-07-15 09:02:46