If I create a list of tuples lst = [(0,5), (5,0), (2,2)] and use min(lst), it returns (0,5).
How does python decide which tuple to be the smallest?
Is it using first element of tuple to make a decision?
How should I change it to return minimum sum of tuple assuming there are only 2 elements in tuples?
You can use a custom key with min.
lst = [(0,5), (5,0), (2,2)]
res = min(lst, key=lambda x: sum(x))
# (2, 2)
To understand how min(lst) works in general, see How does the min/max function on a nested list work?
If you wish to retrieve element with minimum sum sorted by first element, you can specify a tuple key:
lst2 = [(0,5), (5,0), (2,2), (1,3)]
res = min(lst2, key=lambda x: (sum(x), x[0]))
# (1, 3)
Without using the tuple key, the result above would be (2,2).
Related
This is the list I started with
names = ["Alice", "Beatrice", "Amarnae", "Zootrope"]
The last three items all have 4 vowels each
Created a sorted list based on the count of vowels. Got the one shown below
mylist = [(3, 'Alice'), (4, 'Amarnae'), (4, 'Beatrice'), (4, 'Zootrope')]
I need to return/find the 1st occurrence of the max quantity
print(max(mylist))
which returns
(4, 'Zootrope')
Ask: I need to return as that is the first occurrence of the name in the original list
(4, 'Beatrice')
I have tried a few different things (incl. mylist.sort(key = lambda x: (x[0], x[1]) .. but doesn't seem to work.
Your mylist is not created with the original item order retained in the first place, hence the issue.
You can use a list comprehension like this to create mylist:
mylist = [(sum(c in 'aeiou' for c in name.lower()), name) for name in names]
which results in the following value for mylist, retaining the original item order:
[(3, 'Alice'), (4, 'Beatrice'), (4, 'Amarnae'), (4, 'Zootrope')]
Since max returns the first item with the maximum value, you can then simply use max with a key function that returns just the first item in the tuple for comparison, since you don't want the lexicographical order of the second item to be taken into account:
max(mylist, key=lambda t: t[0])
which returns:
(4, 'Beatrice')
Demo: https://replit.com/#blhsing/SwelteringFlakyDividend
I need to find the smallest value in a list. The list has sublists which contains tuples. I need to find the smallest value in all of those tuples, but it can only include the first 3 values. I managed to achieve with the following code, but I want it to look cleaner.
lst = [[(1, 2, 3, 50)], [(0.2, 0.4, 2, 0.1)], [(0.6, 0.8, 1.2, 0.05)]]
def FitScoreSearch3(fitscores):
fitscores2 = []
for x in fitscores:
for y in x:
for z in y[:3]:
fitscores2.append(z)
return min(fitscores2)
The output is 0.2 as it should be. The output can't be 0.05.
Do your sublists always contain just a single tuple? If so,
def FitScoreSearch3(fitscores):
return min(min(x[0][:3]) for x in fitscores)
If the sublists are allowed to contain several tuples:
def FitScoreSearch3(fitscores):
return min(min(y[:3]) for x in fitscores for y in x)
In both cases, this swaps your loops for generator expressions. Also, instead of collecting all the numbers into one big list and then do the min(), the above compute the min() first on the tuple (or rather the first 3 elements of the tuple), after which the global minimum value is computed as the min() of all these "sub-min values". As this does not create an additional data structure, it's faster.
min([value for sublist in lst for value in sublist[0][:3]])
In this code lst2 contains all the values of the first 3 elements of each tuple.
lst2 = [ x for sublist in lst for tpl in sublist for x in tpl[:3] ]
print(min(lst2)) # 0.2
You could do something like -
def fitScoreSearch3(fitScores):
lst = list(map(lambda x: list(x[0][:3]), fitScores))
minimum = min(list(map(min, lst)))
return minimum
I have a list of tuples (x, ind) where x is the item and ind is it's target index in the resulting list. The list is in random order, but it can be assumed that if there are N items in the list, the values of ind in the tuples will be in [0,N) without repetition (i.e. all the valid indices will exist exactly once). How do I get a list where each tuple's position is ind?
Please do not confuse with the many existing answers of how to sort by key.
Obviously, sorting by the ind key is easy, but there would be the unnecessary extra O(n*logn) cost to what should be a O(n) operation because of the aforementioned assumption about ind values.
So:
l = [('item1',1), ('item0',0), ('item2',2), ('item4',4), ('item3',3)]
l2 = magic_rearrange(l, key=lambda x: x[1])
print(l2)
Should give:
[('item0',0), ('item1',1), ('item2',2), ('item3',3), ('item4',4)]
Assuming your indices are unique, here's one way. You can initialise a new list and just insert elements in their right position.
def magic_rearrange(l1):
l2 = [None] * len(l1)
for i in l1:
l2[i[1]] = i
return l2
And a demo:
>>> l = [('item1',1), ('item0',0), ('item2',2), ('item4',4), ('item3',3)]
>>> magic_rearrange(l)
[('item0', 0), ('item1', 1), ('item2', 2), ('item3', 3), ('item4', 4)]
There's a quicker way to do this, if you use numpy's fancy indexing.
import numpy as np
def magic_rearrange(l1):
l2 = np.repeat(None, len(l1))
l2[[x[1] for x in l1]] = l1
return l2
And a demo:
>>> magic_rearrange(l)
array([('item0', 0), ('item1', 1), ('item2', 2), ('item3', 3), ('item4', 4)], dtype=object)
Create the list first and then replace:
def magic_rearrange(l, key):
# creates list to not change original list
new_list = list(l)
# reorder on new list
for original_index, new_index in enumerate(map(key, l)):
new_list[new_index] = l[original_index]
return new_list
Here you go.
def magic_rearrange (input_list, key = lambda x: x):
result_list = [None] * len (input_list)
for p in input_list:
result_list[key (p)] = p
return result_list
We just create a list of the desired length, and then put each element in its place.
The order of operations can be arbitrary, but each element will eventually get to its position in the resulting list.
This is O(N) if copying a single list element and obtaining the key are both O(1).
The key = lambda x: x is for the default order, which is comparing the whole elements (however useless since the result is just list(range(N))).
I'm trying to write a function that takes in
a list of tuples with partygoers names and their priority and
the max number of people that can get it. I'm currently trying to put tuples in ascending order based on one of its elements.
I have a list or tuples:
alist =[('Carlos', 1), ('Gretchen', 8), ('Abby', 6),('Sam', 4)]
so far Ive made a list of all of the numbers in order with this code:
def party_time(alist,maxnum):
newlist = []
finallist=[]
while len(finallist) < maxnum:
for tup in alist:
rank = tup[1]
newlist.append(rank)
newlist.sort()
newlist = [1,4,6,8]
Is there a way to use a for loop to go through newlist and index the tuple by using the number in newlist? Or will it just index where the number is in the tuple?
This should do it:
def party_time(alist, maxnum):
sorted_list = sorted(alist, key=lambda p: p[1], reverse=True)
return sorted_list[:maxnum]
I have a list of tuples:
lst = [('654', '2.12', '86'), ('2', '756'), ('5', '1.77', '71'), ('1.65', '55')]
The function
num = min(lst,key=lambda x: abs(float(x[1]) - 2))
looks up each number at position x[1] inside each tuple and outputs the tuple where x[1] is the closest to 2. Is it possible to adjust the function so that it looks up only tuples with len == 3?
And if it's so I want then to output that tuple and the following 2-item one at the same time. E.g. for the above the final result should be:
[('654', '2.12', '86'), ('2', '756')] and with this I think the for loop will be enough so I think I'll manage.
If the list always alternates between 3-tuple and 2-tuple, you could use
zip(*[iter(lst)]*2)
to group the items into pairs. Then you can use min essentially as you had before:
In [39]: min(zip(*[iter(lst)]*2),key=lambda (x,y): abs(float(x[1]) - 2))
Out[39]: (('654', '2.12', '86'), ('2', '756'))
Lambdas can only hold expressions, so you are limited to ising a conditional expression:
lambda x: abs(float(x[1]) - 2) if len(x) == 3 else float('inf')
but that'll only return a 3-element tuple. The key function can only ever take one element in the sequence into account.
If you always have a 2-element tuple following your 3-element tuples, you'd need to group them together, then determine the minimum from among those paired tuples (as unutbu's answer does).
You can just:
num = min([el for el in lst if len(el)==3], key=lambda x: abs(float(x[1]) - 2))
And this highlights the problem, you are using heterogenous data in your list. If all the tuples are not the same thing they probably don't belong to the same list.
You can filter the list using a generator expression:
num = min((t for t in list if len(t) == 3), key=lambda x: abs(float(x[1]) - 2))