Sorting lists in dictionary - python

Could someone please explain how I could sort a list in dictionary? For example:
B = {'Mary': [(850, 1000), (9, 10), (1000, 3000), (250, 550)], 'john': [(500, 1000), (800,3000), (20, 100), (5, 36)]}
Using the 'sorted' function, how do I sort it in ascending order based on the first value in the list? Likewise, how do I sort it in ascending order based on the second value in the list?
Many thanks

I would iterate through your items, then in-place sort based on the first element of each tuple.
B = {
'Mary': [(850, 1000), (9, 10), (1000, 3000), (250, 550)],
'john': [(500, 1000), (800,3000), (20, 100), (5, 36)],
}
for item in B:
B[item].sort(key = lambda i: i[0])
Output
{
'john': [(5, 36), (20, 100), (500, 1000), (800, 3000)],
'Mary': [(9, 10), (250, 550), (850, 1000), (1000, 3000)]
}

You have to use its key argument. Key is a function which takes the element of the iterable as an agrument and returns the value on which sorting is based:
for e in B:
B[e] = sorted(B[e], key=lambda x: x[Element_ID])
Element ID is the index of the element on which you want to base your sort. So it will be 1 if you want to sort according to the second element and 0 if you want to sort according to the first element.
EDIT:
Also it would be faster to use list's sort method instead of sorted:
for e in B:
B[e].sort(B[e], key=lambda x: x[Element_ID])

Related

How to get best two tuples out of a large list of tuples

I have a Python list contains lots of tuples. I want to find the best two tuples such that which have the best two max range values in it.
list_ = [(55, 55), (77, 81), (95, 129)]
So in this example, I should be able to recover the (77, 81), (95, 129). Because 81-77 and 129-95 gives the largest range.
How can I do this in Python?
heapq.nlargest with a custom key should do the trick:
from heapq import nlargest
list_ = [(55, 55), (77, 81), (95, 129)]
result = nlargest(2, list_, key = lambda x: x[1] - x[0])
def getMaxTwoTuples(list_):
max_tuple = []
for i in range(2):
max_tuples = [i[0]+ i[1] for i in list_]
m = max(max_tuples)
index = max_tuples.index(m)
max_tuple.append(list_[index])
list_.pop(index)
return max_tuple

How to get the highest 4 tuple values?

I am trying to get the highest 4 values in a list of tuples and put them into a new list. However, if there are two tuples with the same value I want to take the one with the lowest number.
The list originally looks like this:
[(9, 20), (3, 16), (54, 13), (67, 10), (2, 10)...]
And I want the new list to look like this:
[(9,20), (3,16), (54, 13), (2,10)]
This is my current code any suggestions?
sorted_y = sorted(sorted_x, key=lambda t: t[1], reverse=True)[:5]
sorted_z = []
while n < 4:
n = 0
x = 0
y = 0
if sorted_y[x][y] > sorted_y[x+1][y]:
sorted_z.append(sorted_y[x][y])
print(sorted_z)
print(n)
n = n + 1
elif sorted_y[x][y] == sorted_y[x+1][y]:
a = sorted_y[x]
b = sorted_y[x+1]
if a > b:
sorted_z.append(sorted_y[x+1][y])
else:
sorted_z.append(sorted_y[x][y])
n = n + 1
print(sorted_z)
print(n)
Edit: When talking about lowest value I mean the highest value in the second value of the tuple and then if two second values are the same I want to take the lowest first value of the two.
How about groupby?
from itertools import groupby, islice
from operator import itemgetter
data = [(9, 20), (3, 16), (54, 13), (67, 10), (2, 10)]
pre_sorted = sorted(data, key=itemgetter(1), reverse=True)
result = [sorted(group, key=itemgetter(0))[0] for key, group in islice(groupby(pre_sorted, key=itemgetter(1)), 4)]
print(result)
Output:
[(9, 20), (3, 16), (54, 13), (2, 10)]
Explanation:
This first sorts the data by the second element's value in descending order. groupby then puts them into groups where each tuple in the group has the same value for the second element.
Using islice, we take the top four groups and sort each by the value of the first element in ascending order. Taking the first value of each group, we arrive at our answer.
You can try this :
l = [(9, 20), (3, 16), (54, 13), (67, 10), (2, 10)]
asv = set([i[1] for i in l]) # The set of unique second elements
new_l = [(min([i[0] for i in l if i[1]==k]),k) for k in asv]
OUTPUT :
[(3, 16), (2, 10), (9, 20), (54, 13)]

List to group of tuples

I have a list like
A = [1,10,50,100,500]
I need to group by 2 numbers with proper sequence. Output is like this,
B = [(1,9),(10,49),(50,99),(100,499)]
I have tried via yield:
def group(lst, n):
for i in range(0, len(lst), n):
val = lst[i:i+n]
if len(val) == n:
yield tuple(val)
print(list(group([1,10,50,100,500], 2)))
You can simply zip the sequence with itself (without the first item):
A = [1,10,50,100,500]
def group(lst):
for i, j in zip(A, A[1:]): # pairwise items
yield (i, j-1) # decrement second item by 1
>>> list(group(A))
[(1, 9), (10, 49), (50, 99), (100, 499)]
Or use it as list-comprehension without intermediate function:
>>> [(i, j-1) for i, j in zip(A, A[1:])]
[(1, 9), (10, 49), (50, 99), (100, 499)]
You can use list comprehension with islice and zip to iterate pairwise over the list:
>>> from itertools import islice
>>> A = [1,10,50,100,500]
>>> [(x, y - 1) for x, y in zip(A, islice(A, 1, None))]
[(1, 9), (10, 49), (50, 99), (100, 499)]
In above islice returns an iterator that starts from the second element on A. islice is used instead of normal slicing so that the original list doesn't need to be copied:
>>> s = list(islice(A, 1, None))
>>> s
[10, 50, 100, 500]
Then zip is used to create iterable pairs of items from the original list and iterator:
>>> pairs = list(zip(A, s))
>>> pairs
[(1, 10), (10, 50), (50, 100), (100, 500)]
And finally list comprehension iterates over the pairs to create the result:
>>> [(x, y - 1) for x, y in pairs]
[(1, 9), (10, 49), (50, 99), (100, 499)]

How to merge repeated elements in list in python?

I have a list of coordinate like:
list_coordinate =[(9,0),(9,1),(9,3) ... (53,0),(53,1),(53,3)...(54,0),(54,1)..]
value = []
for m in range(0,len(list_coordinate)):
if m != len(list_coordinate)-1:
if list_coordinate[m][0]==list_coordinate[m+1][0]:
value.append(list_coordinate[m][0])`
Output of this code:
value = [9,9 ,9,...,53,53,53,...,54,54,54,54...]
I want to merge this value list for similar element and want output as:
Expected output:
[9,53,54]
If you prefer one-liners, you can do it like this:
list(set(map(lambda x: x[0], list_coordinate)))
It will output:
[9, 53, 54]
Note: As set is being used in the code, ordering of the elements is not guaranteed here.
you can use itertools.groupby
from itertools import groupby
value = [9,9 ,9,53,53,53,54,54,54,54]
g = [k for k,_ in groupby(value)]
print(g)
which produces
[9, 53, 54]
and it is guaranteed to be in the same order as the input list (if it matters).
Basically
groupby(iterable[, keyfunc])
groups the elements in the iterable, passing to a new group when the key function changes.
If the key function is omitted, the identity function is assumed, and the key for the group will be each element encountered.
So as long as the elements in value stay the same, they will be grouped under the same key, which is the element itself.
Note: this works for contiguous repetitions only. In case you wanted to get rid of re-occurring duplicates, you should sort the list first (as groupby docs explains)
As per your comment below, in case you wanted to operate on the coordinates directly
list_coordinate = [(9,0), (9,1), (9,3), (53,0), (53,1), (53,3), (54,0), (54,1)]
g = [k for k,_ in groupby(list_coordinate, lambda x: x[0])]
print(g)
produces the same output
[9, 53, 54]
You could use an OrderedDict for both of your cases. Firstly for just the x coordinates:
list_coords = [(9, 0), (9, 1), (9, 3), (53, 0), (53, 1), (53, 3), (54, 0), (54, 1)]
merged = OrderedDict()
for coord in list_coords:
merged[coord[0]] = 1
print merged.keys()
Giving:
[9, 53, 54]
Note, if for example (9, 0) was repeated later on, it would not change the output.
Secondly, for whole coordinates. Note, the data has (10 ,0) repeated 3 times:
list_coords = [(9, 0), (9, 1), (9, 3), (10, 0), (10, 0), (10, 0), (53, 0), (53, 1), (53, 3), (54, 0), (54, 1)]
merged = OrderedDict()
for coord in list_coords:
merged[coord] = 1
print merged.keys()
Giving:
[(9, 0), (9, 1), (9, 3), (10, 0), (53, 0), (53, 1), (53, 3), (54, 0), (54, 1)]
Why don't you use a set:
{ k[0] for k in list_coordinate }

Remove tuple from list of tuples if certain condition is met

I have a list of tuples that look like this;
ListTuples = [(100, 'AAA'), (80, 'BBB'), (20, 'CCC'), (40, 'DDD')]
I want to remove the tuples when the first element of the tuple is less than 50. The OutputList will look like this;
OutputList = [(100, 'AAA'), (80, 'BBB')]
How can this be done in python?
Thank you very much for your help.
You can easily do it as:
out_tup = [i for i in in_tup if i[0] >= 50]
[Out]: [(100, 'AAA'), (80, 'BBB')]
This simply creates a new list of tuples with only those tuples whose first element is greater than or equal to 50. Same result, however the approach is different. Instead of removing invalid tuples you accept the valid ones.
You can also do:
>>> OutputList = filter(ListTuples, lambda x: x[0] >= 50)
>>> OutputList
[(100, 'AAA'), (80, 'BBB')]
Code snippet for timing the solutions given by sshashank124 and Alex Thornton:
ListTuples = [(100, 'AAA'), (80, 'BBB'), (20, 'CCC'), (40, 'DDD')]
import timeit
timeit.timeit('[i for i in ListTuples if i[0] >= 50]', globals=globals(), number=1000000)
>>> 0.6041104920150246
timeit.timeit('filter(lambda x: x[0] >= 50, ListTuples)', globals=globals(), number=1000000)
>>> 0.3009479799948167
The build-in filter() solution is faster for this example.
We can Do this with simple counter and a new list:
new = []
for i in ListTuples:
for j in i:
if ( counter % 2 == 0 ):
if ( j > 50):
new.append(i)
counter = counter +1
output :
[(100, 'AAA') , (80, 'BBB')]
Try this,
>>> ListTuples = [(100, 'AAA'), (80, 'BBB'), (20, 'CCC'), (40, 'DDD')]
>>> new=[]
>>> for i in ListTuples:
if i[0]>50:
new.append(i)
>>> new
[(100, 'AAA'), (80, 'BBB')]
>>>
ListTuples = [(100, 'AAA'), (80, 'BBB'), (20, 'CCC'), (40, 'DDD')]
out=[]
for item in ListTuples:
if item[0]>50:
out.append((item[0],item[1]))
print(out)

Categories

Resources