简体   繁体   English

在Python3中计算列表中相等的元组元素

[英]Count equal tuple-elements of a list in Python3

The code here works for me. 这里的代码适合我。 But I am new to Python and want to know and learn if there is a more elegant or pythonic way to do that job. 但我是Python的新手,想知道并了解是否有更优雅或pythonic的方式来完成这项工作。

There is a list of two-element-tuples. 有一个包含两元素元组的列表。 I want to join equal list elements and store the count of equal elements as a third tuple-element (the first in front of the other two-tuple elements). 我想加入相等的列表元素并将相等元素的数量存储为第三个元组元素(在其他两元组元素前面的第一个)。

#!/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()

Similar to the other answers, but for any tuple dimension: 与其他答案类似,但对于任何元组维度:

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 is definitely very useful (and idiomatic) for this, but it's good to remember that it's easy to construct a similar structure with a plain dict : 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      

Its properties are ideal for this task. 它的属性非常适合这项任务。 If you're not familiar with dict s, more amazement is awaiting you. 如果你对dict不熟悉,那么更多的惊喜正等着你。 :) :)

Using a combination of a Counter and a list comprehension, we can do this fairly quickly. 使用Counter和list comprehension的组合,我们可以相当快地完成此操作。 It will result in a new tuple though, since a tuple is immutable. 但是它会产生一个新的元组,因为元组是不可变的。

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)]

The org_count variable looks like this at the end of the script: org_count变量在脚本末尾看起来像这样:

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

It's important to note that the Counter is a dictionary subclass, thus unordered. 重要的是要注意Counter是一个字典子类,因此是无序的。 That means you final list can be in a different order than the original org variable. 这意味着您的最终列表可以与原始org变量的顺序不同。 I made the assumption that this was alright, because duplicates would be compressed into a single entry, thus messing up the order. 我假设这没关系,因为重复会被压缩成一个条目,从而弄乱了订单。

In the list comprehension, I utilize the unique set of org to prevent duplicate entries. 在列表理解中,我利用唯一的org set来防止重复的条目。

for o in set(org)

An easier way to do what you are doing would be to use collections.Counter and list comprehension - 一个更简单的方法来做你正在做的事情就是使用collections.Counter和list comprehension -

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

Please note, this would not preserve the order from the original list. 请注意,这不会保留原始列表中的订单。

Demo - 演示 -

>>> 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)]

If you want to preserve the order, I would suggest you use a set to record the elements that are already seen and use collections.Counter() for counting. 如果你想保留订单,我建议你使用一个集来记录已经看过的元素,并使用collections.Counter()进行计数。 Example - 示例 -

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)

Demo - 演示 -

>>> 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)]

Also, just a suggestion , a better way to do the following - 此外,只是一个建议,一个更好的方法来做到以下 -

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

Is to use any() , Example - 是使用any() ,示例 -

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)

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

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