2015-09-10 129 views
2

這裏的代碼適用於我。但是我對Python很陌生,想知道並學習是否有更優雅或Python的方式來完成這項工作。在Python3中計算一個列表的相等元組元素

有一個兩元素元組的列表。我想加入相同的列表元素,並將相等元素的數量作爲第三個元組元素(其他兩元組元素前面的第一個元素)存儲。

#!/usr/bin/env python3 
# -*- coding: utf-8 -*- 

org = [ (12, 4), 
     ( 8, 4), 
     (12, 8), 
     (12, 8) ] 

# should result in 
# [ (1, 12, 4), 
# (1, 8, 4), 
# (2, 12, 8) ] 


def count_element(count_in, e): 
    """ 
     How often does 'e' appear in 'count_in'. 
    """ 
    count = 0 
    for x in count_in: 
     if x == e: 
      count += 1 
    return count 


def has_element(look_in, e): 
    """ 
     'look_in' is a three-element tuple 
     'e' is a two-element tuple 
    """ 
    for x, y, z in look_in: 
     if y == e[0] and z == e[1]: 
      return True 
    return False 


def main(): 
    result = [] 

    for i in org: 
     if has_element(result, i): 
      continue 
     c = count_element(org, i) 
     resi = (c, i[0], i[1]) 
     result += [resi] 

    print(org) 
    print(result) 


if __name__ == '__main__': 
    main() 
+0

你能解釋codereview上的代碼和stackoverflow上的代碼之間的差異嗎?我的代碼只是一個簡單的例子來描述我的算法問題。這不是生產性的代碼,需要審查。 – buhtz

+0

爲了達到你想要的效果,'(12,4)'和'(4,12)'是否一樣? – dawg

+0

不,它是不同的。 – buhtz

回答

5

到其他的答案相似,但對於任何元組尺寸:

org = [(12, 4), (8, 4), (12, 8), (12, 8), (4, 3, 2, 1)] 

from collections import Counter 
[(count,) + item for item, count in Counter(org).items()] 
# [(2, 12, 8), (1, 12, 4), (1, 4, 3, 2, 1), (1, 8, 4)] 

Counter絕對是這個非常有用的(地道),但它是很好的記住它是容易構造一個類似的結構與普通dict

counter = dict() 
for item in org: 
    if item not in counter: 
     counter[item] = 1 
    else: 
     counter[item] += 1 
    # Alternatively, just: counter[item] = counter.get(item, 0) + 1  

它的屬性是這項任務的理想選擇。如果你不熟悉dict,更多的驚喜等待着你。 :)

2

使用Counter和列表理解的組合,我們可以很快做到這一點。它會產生一個新的元組,因爲元組是不可變的。

from collections import Counter 

org = [ (12, 4), 
     ( 8, 4), 
     (12, 8), 
     (12, 8) ] 
counts = Counter(org) 
org_counts = [(counts[o], o[0], o[1]) for o in set(org)] 

org_count變量看起來像這樣在腳本的末尾:

[(2, 12, 8), (1, 12, 4), (1, 8, 4)] 

重要的是要注意的是,Counter是一本字典的子類,因而無序是非常重要的。這意味着您的最終名單可能與原始org變量的順序不同。我假設這是正確的,因爲重複項會被壓縮成單個項目,從而搞亂了順序。

在列表理解中,我利用org的唯一set來防止重複條目。

for o in set(org) 
+0

哇。這很神奇。 – buhtz

+0

不需要設置 - 只需爲'計數'中的o,或者甚至爲o計數counts.items()'。 – lvc

1

更簡單的方法做你正在做的事情是使用collections.Counter和列表理解 -

import collections 
def main() 
    result = [(v,) + k for k,v in collections.Counter(org).items()] 
    print(org) 
    print(result) 

請注意,這不會保留原始列表中的順序。

演示 -

>>> org = [ (12, 4), 
...   ( 8, 4), 
...   (12, 8), 
...   (12, 8) ] 
>>> 
>>> result = [(v,) + k for k,v in collections.Counter(org).items()] 
>>> result 
[(2, 12, 8), (1, 12, 4), (1, 8, 4)] 

如果你想保留的順序,我建議你使用一組以記錄已經看到的元素,並使用collections.Counter()計數。示例 -

import collections 
def main(): 
    result = [] 
    seen = set() 
    counts = collections.Counter(org) 
    for x in org: 
     if x not in seen: 
      result.append((counts[x],) + x) 
      seen.add(x) 

演示 -

>>> org 
[(12, 4), (8, 4), (12, 8), (12, 8)] 
>>> 
>>> result = [] 
>>> seen = set() 
>>> counts = collections.Counter(org) 
>>> for x in org: 
...  if x not in seen: 
...   result.append((counts[x],) + x) 
...   seen.add(x) 
... 
>>> result 
[(1, 12, 4), (1, 8, 4), (2, 12, 8)] 

而且,只是一個建議,一個更好的方式做以下 -

def has_element(look_in, e): 
    """ 
     'look_in' is a three-element tuple 
     'e' is a two-element tuple 
    """ 
    for x, y, z in look_in: 
     if y == e[0] and z == e[1]: 
      return True 
    return False 

就是用​​,例如 -

def has_element(look_in, e): 
    """ 
     'look_in' is a three-element tuple 
     'e' is a two-element tuple 
    """ 
    return any(y == e[0] and z == e[1] for _, y, z in look_in) 
+0

我會記住'any()'爲我未來的工作。但是這裏的優勢是什麼?你的代碼很難讀取人類。 – buhtz

+0

什麼更難?第二個?第二個有保留訂單的好處。 –

+0

第一個和其他人完全一樣,所以我不明白這是多麼困難。 –