简体   繁体   中英

How can I convert this tuple of tuples into a count of its elements?

I have this tuple of tuples:

TupleOfTuples = (('Venue1', 'Name1'), ('Venue1', 'Name2'), 
                 ('Venue2', 'Name3'), ('Venue3', 'Name4'), 
                 ('Venue3', 'Name5'), ('Venue3', 'Name6'))

I want to convert it to get a result like this:

Output = (('Venue1', 2), ('Venue2', 1), ('Venue3', 3))

In this case, Output contains ('Venue1', 2) , for example, where 2 is the number of times 'Venue1' occurred in TupleOfTuples .

I tried using len() to count the number of occurrences, but it does not work given that TupleOfTuples is not a single tuple but a tuple of tuples.

How can this be done in Python2.7?

Use collections.Counter() to count how many occurrences you have:

from collections import Counter

Output = Counter(t[0] for t in TupleOfTuples).items()

A Counter() is a dictionary where keys are mapped to counts; by passing in a generator expression it will do the counting for you. Because it is a dictionary subclass, dict.items() can then be used to produce a list of (key, count) tuples.

This does produce a list ; simply call tuple() on that if you insist on having a tuple here.

Demo:

>>> from collections import Counter
>>> TupleOfTuples = ( ('Venue1', 'Name1'), ('Venue1', 'Name2'), ('Venue2', 'Name3'), ('Venue3', 'Name4'), ('Venue3', 'Name5'), ('Venue3', 'Name6') )
>>> Counter(t[0] for t in TupleOfTuples).items()
[('Venue1', 2), ('Venue3', 3), ('Venue2', 1)]

You can accomplish this quickly and easily using zip(*TupleOfTuples)[n] to get a sequence of all elements to be counted (where n is the index of the element in each TupleOfTuples tuple to count; in this case, 0 ), then iterating through the result to get a count for each unique element.

Here's what it looks like:

TupleOfElements = zip(*TupleOfTuples)[0]
Output = tuple((e, TupleOfElements.count(e)) for e in set(TupleOfElements))

I'll explain what's going on:

zip(*TupleOfTuples)[0] takes your input sequence and transposes it . We want the zero'th element from each TupleOfTuples element, so we take [0] from the result. We assign that sequence to TupleOfElements . (If you wanted to count the Name* elements instead, for instance, you would use zip(*TupleOfTuples)[1] .)

tuple((e, TupleOfElements.count(e)) for e in set(TupleOfElements)) creates the Output you want by iterating through TupleOfElements and returning an element-count pair for each unique element: TupleOfElements contains all TupleOfTuples elements in the correct quantity , so we can use TupleOfElements.count(uniqueElement) will tell us how many occurrences of uniqueElement there are. We don't need or want to recheck any specific element more than once, though, so we iterate through set(TupleOfElements) , which will contain exactly one of each element present. We assign the result to Output , and we're done!

  • Note: This will return Output as a tuple . If you want it as a list , replace the tuple(..) in the second line with [..] , keeping the contents the same.

  • On performance: This code seems to run considerably faster than Martijn's very good solution using collections.Counter -- around 3.5x faster for the example TupleOfTuples given, and about 1.25x faster in a much larger but much simpler 88,888-element test I made up to satisfy my own curiosity-- I should imagine because it replaces the dictionary-creation step with a tuple and iterator. It may not be quite as elegant, but I'm a bit proud of it all the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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