Sort criterion for 2 lists - python

I have two lists:
a = [2,3,1,4]
b=[two, three, one, four]
I need to sort the first list in ascending order, but I need the second list ( made up of strings) to follow the same sorting.
That is, I expect to get the following result:
a = [1,2,3,4]
b = [one, two, three, four]
does anyone have a simple way to do this?

aa, bb = zip(*sorted(zip(a, b)))
BTW, you will need to quote the items in the second list, unless those are variable references.
The inner zip puts the two lists together into one tuple:
[(2, 'two'), (3, 'three'), (1, 'one'), (4, 'four')]
The sorted does the sort. Tuples sort by their first key:
[(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
The outer zip & * operator usage is an "unzip a list" pythonic trick.

Use: sorted(zip(a,b))
We are basically zipping the two lists together. They need to have same length.

Combine the two lists into a list of two-element tuples and sort it:
mylist = [
(2, "two"),
(3, "three"),
(1, "one"),
(4, "four")
]
mylist.sort()
It will be sorted in order of the first element.

Related

Problem in getting unique elements from list of tuples

I got sample input as a=[(1,2),(2,3),(1,1),(2,1)], and the expected ouput is a=[(1,2),(2,3),(1,1)].
Here, (2,1) is removed, since the same combinational pair (1,2) is already available. I tried below code to remove duplicate pairs
map(tuple, set(frozenset(x) for x in a))
However, the output is [(1, 2), (2, 3), (1,)]. How to get (1,1) pair as (1,1) instead of (1,).
You can use a dict instead of a set to map the frozensets to the original tuple values. Build the dict in reversed order of the list so that duplicating tuples closer to the front can take precedence:
{frozenset(x): x for x in reversed(a)}.values()
This returns:
[(1, 2), (2, 3), (1, 1)]
This is one approach using sorted
Ex:
a=[(1,2),(2,3),(1,1),(2,1)]
print set([tuple(sorted(i)) for i in a])
Output:
set([(1, 2), (2, 3), (1, 1)])

Remove element from itertools.combinations while iterating?

Given a list l and all combinations of the list elements is it possible to remove any combination containing x while iterating over all combinations, so that you never consider a combination containing x during the iteration after it is removed?
for a, b in itertools.combinations(l, 2):
if some_function(a,b):
remove_any_tup_with_a_or_b(a, b)
My list l is pretty big so I don't want to keep the combinations in memory.
A cheap trick to accomplish this would be to filter by disjoint testing using a dynamically updated set of exclusion values, but it wouldn't actually avoid generating the combinations you wish to exclude, so it's not a major performance benefit (though filtering using a C built-in function like isdisjoint will be faster than Python level if checks with continue statements typically, by pushing the filter work to the C layer):
from future_builtins import filter # Only on Py2, for generator based filter
import itertools
blacklist = set()
for a, b in filter(blacklist.isdisjoint, itertools.combinations(l, 2)):
if some_function(a,b):
blacklist.update((a, b))
If you want to remove all tuples containing the number x from the list of combinations itertools.combinations(l, 2), consider that you there is a one-to-one mapping (mathematically speaking) from the set itertools.combinations([i for i in range(1,len(l)], 2) to the itertools.combinations(l, 2) that don't contain the number x.
Example:
The set of all of combinations from itertools.combinations([1,2,3,4], 2) that don't contain the number 1 is given by [(2, 3), (2, 4), (3, 4)]. Notice that the number of elements in this list is equal to the number of elements of combinations in the list itertools.combinations([1,2,3], 2)=[(1, 2), (1, 3), (2, 3)].
Since order doesn't matter in combinations, you can map 1 to 4 in [(1, 2), (1, 3), (2, 3)] to get [(1, 2), (1, 3), (2, 3)]=[(4, 2), (4, 3), (2, 3)]=[(2, 4), (3, 4), (2, 3)]=[(2, 3), (2, 4), (3, 4)].

How to sort dictionary on first element of the key (tuple)

I have a dictionary where each key is a tuple of values, I want to use the sorted() method to sort the dictionary on the very first element of my tuple. My code looks like this:
def mapData(header_list, dict_obj):
master_dict = {}
client_section_list = []
for element in header_list:
for row in dict_obj:
if (row['PEOPLE_ID'], row['DON_DATE']) == element:
client_section_list.append(row)
element = list(element)
element_list = [client_section_list[0]['DEDUCT_AMT'],
client_section_list[0]['ND_AMT'],
client_section_list[0]['DEDUCT_YTD'],
client_section_list[0]['NONDEDUCT_YTD']
]
try:
element_list.append((float(client_section_list[0]['DEDUCT_YTD']) +
float(client_section_list[0]['NONDEDUCT_YTD'])
))
except ValueError:
pass
element.extend(element_list)
element = tuple(element)
master_dict[element] = client_section_list
client_section_list = []
return sorted(master_dict, key=lambda key: key[master_dict[(1)]]
The last line is where I'm trying to find a way to sort it. My tuple looks like this:
(312178078,6/22/15,25,0,25,0,25.0)
Not entirely sure what you are trying to do, particularly what that function is supposed to return. I assume that you want to return the dictionary sorted by the first element in the key-tuples.
For this, there are two things to note:
Tuples are by default sorted by their first element (and if those are the same, then by the second, and so on), so no special key function is required
Regular dictionaries are unordered, i.e. they can not be permanently sorted in any order; you can only sort their items as a list, or use that list to create an OrderedDict instead
Some minimal example:
>>> d = {(2,4): 1, (1,3): 2, (1,2): 3, (3,1): 4}
>>> sorted(d)
[(1, 2), (1, 3), (2, 4), (3, 1)]
>>> sorted(d.items())
[((1, 2), 3), ((1, 3), 2), ((2, 4), 1), ((3, 1), 4)]
>>> collections.OrderedDict(sorted(d.items()))
OrderedDict([((1, 2), 3), ((1, 3), 2), ((2, 4), 1), ((3, 1), 4)])
In your case, you probably want this:
return collections.OrderedDict(sorted(master_dict.items()))
As #tobias_k has mentioned, sorted sorts tuples by its elements with decreasing priority, e.g. if you take a tuple (a, b, c) the highest sorting priority goes to a, then goes b etc (by default sorted uses object's comparison methods and this is how tuple comparison works). So sorted(master_dict) is all you need if you want a list of sorted keys, yet I believe you really want to leave the values
sorted(master_dict.items(), key=lambda key: key[0])
dict.items returns tuples of form (key, value) so here you need to specify the sorting key.

Union with tuples Python

import itertools
list_with_tuples=[(1,), (2,), (3,)]
pairs = itertools.combinations(list_with_tuples, 2)
for pair in pairs:
print(pair)
so the result of pairs is :
((1,),(2,)) ,
((1,),(3)) ,
((2,),(3,))
How I can union them?
After union I want to do a dictionary like:
di={ (1,2): value1, (1,3): value2, (2,3): value3 }
How can I do this?
One way to "union" tuples in python is to simply add them:
>>> (1,) + (2,)
(1, 2)
So you can modify your example to add:
import itertools
list_with_tuples=[(1,), (2,), (3,)]
pairs = itertools.combinations(list_with_tuples, 2)
for left, right in pairs:
print(left + right)
Outputs:
(1, 2)
(1, 3)
(2, 3)
If you need to add n tuples, rather than just 2 of them, you can use sum and specify an initial value of the empty tuple () as the second argument.
Alternatively, as Kevin mentioned in the comments, you can build a new tuple by consuming the output of an itertools.chain, which will likely be more efficient if n is large.
You can use a dict comprehension to do this for you. Iterate over the itertools.combinations, index out the values from the tuple, then create your new tuple as the key and add them for the value.
>>> {(i[0],j[0]) : i[0] + j[0] for i,j in itertools.combinations(list_with_tuples, 2)}
{(1, 2): 3, (1, 3): 4, (2, 3): 5}
You can chain the elements into a single tuple:
from itertools import chain,combinations
list_with_tuples=[(1,), (2,), (3,)]
di = {tuple(chain.from_iterable(comb)):"value" for comb in combinations(list_with_tuples, 2)}
print(di)
{(1, 2): 'value', (1, 3): 'value', (2, 3): 'value'}
It will work for any length combinations.
If you have a another container that has the values you can zip:
from itertools import chain,combinations
list_with_tuples=[(1,), (2,), (3,)]
values = [1,2,3]
di = {tuple(chain.from_iterable(comb)): val for comb,val in zip(combinations(list_with_tuples, 2),values)}
print(di)
{(1, 2): 1, (1, 3): 2, (2, 3): 3}
You can join iterable objects such as tuples and lists together using itertools.chain():
list_with_tuples=[(1,), (2,), (3,)]
pairs = itertools.combinations(list_with_tuples, 2)
for pair in pairs:
print(tuple(itertools.chain(*pair)))
This also has the advantage of being lazy, so you can iterate over the chain one element at a time instead of making a full tuple out of it, if that's what you need. If pair is also a lazy iterator, you probably want to use itertools.chain.from_iterable() instead of the star operator.

How to select increasing elements of a list of tuples?

I have the following list of tuples:
a = [(1, 2), (2, 4), (3, 1), (4, 4), (5, 2), (6, 8), (7, -1)]
I would like to select the elements which second value in the tuple is increasing compared to the previous one. For example I would select (2, 4) because 4 is superior to 2, in the same manner I would select (4, 4) and (6, 8).
Can this be done in a more elegant way than a loop starting explicitly on the second element ?
To clarify, I want to select the tuples which second elements are superior to the second element of the prior tuple.
>>> [right for left, right in pairwise(a) if right[1] > left[1]]
[(2, 4), (4, 4), (6, 8)]
Where pairwise is an itertools recipe you can find here.
You can use a list comprehension to do this fairly easily:
a = [a[i] for i in range(1, len(a)) if a[i][1] > a[i-1][1]]
This uses range(1, len(a)) to start from the second element in the list, then compares the second value in each tuple with the second value from the preceding tuple to determine whether it should be in the new list.
Alternatively, you could use zip to generate pairs of neighbouring tuples:
a = [two for one, two in zip(a, a[1:]) if two[1] > one[1]]
You can use enumerate to derive indices and then make list comprehension:
a = [t[1] for t in enumerate(a[1:]) if t[1][1] > a[t[0]-1][1]]
You can use list comprehension
[i for i in a if (i[0] < i[1])]
Returns
[(1, 2), (2, 4), (6, 8)]
Edit: I was incorrect in my understanding of the question. The above code will return all tuples in which the second element is greater than the first. This is not the answer to the question OP asked.

Categories