[Tutor] how to invert tuples
Steven D'Aprano
steve at pearwood.info
Sun Nov 22 19:39:07 EST 2015
On Sun, Nov 22, 2015 at 09:58:35PM +0100, marcus lütolf wrote:
> dear pythonistas
>
> i have written the code below for identifying tuples occurring twice
> or more times in the list of tuples called "flights".
> 1. Question: How can i modify this code so it does not matter which
> string is first and which is second or (h,i) == (i,h) respectively ?
Modifying your code is perhaps not the best way. It might be better to
start with something different.
a, b, c, d, e, f, g, h, i, j, k, l = ['M' + str(i) for i in range(1, 13)]
flights = [
(h,i), (h,j),(k,f), (k,a), (f,a), (e,f), (e,g), (d,g), (l,c),(l,b),
(c,b),(j,c), (j,k), (c,k), (h,f), (h,d), (f,d), (a,l), (a,g),(e,i),
(e,b,), (i,b), (i,l), (i,k), (l,k), (f,j),(f,b), (j,b),(h,a),(h,g),
(a,g), (d,e), (d,c), (e,c), (i,c), (i,d), (c,d), (f,e,),(f,i),(e,i),
(a,j,), (a,b), (j,b), (h,l), (h,k), (l,k), (l,f), (l,g),(f,g),(b,k),
(b,d), (k,d), (i,a), (i,j), (a,j), (h,c), (h,e), (c,e), (h,j)
]
# Convert from tuples to sets, the hard way:
tmp = []
for x in flights:
tmp.append(frozenset(x))
flights = tmp
# Count how many times each frozen set appears.
from collections import Counter
c = Counter(flights)
# Print duplicate keys.
for key, count in c.items():
if count > 1:
k = tuple(sorted(key)) # Make it prettier to look at.
print "%s appears %d times" % (k, count)
There are a couple of tricks here:
- Use the Counter object to do the counting.
- Use sets instead of tuples.
The problem is that tuples (a, b) care about their order. By definition,
(a, b) is not the same as (b, a). But sets don't care about their order.
We can write sets like {a, b}, which by definition is equal to {b, a}.
Unfortunately, for technical reasons sets can't be used as the key in
dicts or Counters. Fortunately, Python has a frozenset type which can.
So we convert the tuples into frozensets. Above, we do it the hard way.
Of course, there's an easy way too:
# Convert from tuples to sets the easy way:
flights = [frozenset(x) for x in flights]
*Two* easy ways:
flights = map(frozenset, flights)
You are not expected to understand how they work, but you are welcome to
ask if you would like it explained.
Unfortunately, frozensets don't have a particularly pleasant looking
display when printed, for example:
frozenset(['M7', 'M1'])
Not ugly by any means, but rather bulky. So when printing, we convert
back to a tuple with:
tuple(sorted(key))
The call to sorted() ensures that the two items ('M7' and 'M1', say)
always appear in consistent order.
But perhaps it would be better to avoid generating the duplicate flights
in the first place. I'm not sure where your list of flights came from in
the first place, but we can systematically generate all the unique pairs
like this:
locations = ['M' + str(i) for i in range(1, 13)]
unique_pairs = []
for i, a in enumerate(locations):
for b in locations[i+1:]:
unique_pairs.append((a, b))
> 2. Question: On my python file I have written the rather long list of
> tuples in 3 lines. If I break them down in multiple shorter lines the
> for loop will not work through the last tuple.
I'm afraid I don't understand what you mean by this.
--
Steve
More information about the Tutor
mailing list