Index a tuple by calling one of its elements - python

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]

Related

printing out tuples from function

Im making this function that prints the index number with the item from the string but I need it to print out as tuples, for example
[(0, 'dog'), (1, 'pig'), (2, 'cow')]
how would I go about doing this? it just prints each out on one line so far.
this is my code so far.
def my_enumerate(items):
"""return a list of tuples where item is the i'th item """
for item in items:
index = items.index(item)
print(item, index)
my_enumerate(['dog', 'pig', 'cow'])
thank you
def my_enumerate(items):
"""return a list of tuples where item is the i'th item """
l = []
for index in range(len(items)):
t = (index, items[index])
l.append(t)
return l
res = my_enumerate(['x', 'x', 'x'])
print(res)
I would suggest:
def my_enumerate(items):
print([(i, animal) for i, animal in enumerate(items)])
the reason you are printing them one by one is that you are printing them one by one inside the loop, to get all of them at once you will need to create a list and print that at the end of the loop. there are several ways to go about this and m0nte-cr1st0 gave you the most legible one, ill give you something a little shorter:
def my_enumerate(items):
return list(zip(range(len(items)), items))
zip lets you smoosh together 2 lists pairwise
this solution of course assumes you cant just use the built in enumerate
In expression
print(list(enumerate(items)))
part enumerate(['dog', 'pig', 'cow']) will create an iterator over the list of tuples [(0, 'dog'), (1, 'pig'), (2, 'cow')] you want to print , so you can just create a list with this iterator and print it.

Creating multiple lists, putting inside another list, then sorting

I need to be able to:
define a function that accepts two parameters. create two lists, one
with names and another with grades.
put the data from those two lists into a third list, with the grades
corresponding to the name that is in the same place in the first list. i.e:
have the same index value.
then, I need to be able to sort that list in descending order by the
grades.
This is all I have so far:
def gradeAvg(lst1,lst2):
lst1 = ["Jo", "Ji", "Ja"]
lst2 = [[90],[80],[70]]
jo = lst1[0]
ji = lst1[1]
ja = lst1[2]
jogr = str(lst2[0])
jigr = str(lst2[1])
jagr = str(lst2[2])
lst3 = [[jo + jogr],[ji+jigr],[ja+jagr]]
print(lst3)
which gives me this output:
[['Jo[90]'], ['Ji[80]'], ['Ja[70]']]
However, I need my output to be more similar to this:
Kim/98
Lib/96
Mar/95
Nat/92
Ophelia/90
Princ/89
Rhea/87
Is the way I created my lists "OK". And where do I go from here to sort the lists?
No, the way you created your list is not okay, what you want is actually create a list with the elements containing pairs of name and grade, like
[('mar', 95), ('Kim', 98) ...]
You can create this list manually or use built-in zip function
list3 = list(zip(list1, list2))
Then you can sort this list by providing a key function to the sort method on list
list3.sort(key=lambda pair: pair[1], reverse=True)
Here I am sorting based on the grade notice I am returning pair[1] which is grade and reverse=True sorts in descending order.
Then you can simply iterate over list3 and print:
for name, grade in list3:
print('{}/{}'.format(name, grade))
"put the data from those two lists into a third list", that's what zip does.
Step 3 is in the reverse parameter to sorted():
def gradeAvg(lst1,lst2):
for a, b in sorted(zip(lst1, lst2), key=lambda x: x[1], reverse=True):
print("{}/{}".format(a, b))
l1 = ['Kim', 'Lib', 'Mar', 'Nat', 'Ophelia', 'Princ' ,'Rhea']
l2 = [98, 96, 95, 92, 90, 89, 87]
gradeAvg(l1, l2)
output:
Kim/98
Lib/96
Mar/95
Nat/92
Ophelia/90
Princ/89
Rhea/87
def function(names,grades):
return_list = []
for i in range(0,len(names)):
return_list.append( {names[i]:grades[i] }
return_list = sorted(return_list, reverse=True)
for i in range(0,len(a)):
for key in a[i]:
print str(key)+ '/'+str(a[i][key][0])

Rearrange list based on key WITHOUT sorting

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))).

deleting multiple elements without updating till the end

I have two lists:
list_a = [1,5,8]
list_b = [12,4,2,5,7,5,3,6,8]
The elements in list_a correspond to the indices of elements in list_b. Both lists are of size greater than 100.
How can I delete the elements of list_b whose indices are in list_a,
so if you take the lists above the resulting list is [12,2,5,7,3,6]?
Two options:
Create a new list with a list comprehension:
newlist = [el for i, el in enumerate(oldlist) if i not in indices_to_delete]
This will be all the faster if indices_to_delete was a set:
indices_to_delete = set(indices_to_delete)
newlist = [el for i, el in enumerate(oldlist) if i not in indices_to_delete]
because membership testing in a set is O(1) vs. O(n) in a list.
Remove the indices in reverse-sorted order from the list in-place:
for index in sorted(indices_to_delete, reversed=True):
del oldlist[index]
If you don't remove items in reverse sorted order, items with higher indices are moved up as items with lower indices are removed and the rest of your indices_to_delete no longer match the items you needed to remove.
This should accomplish that:
for delidx in reversed(toDelete):
del otherList[delidx]
Also, using a list comprehension:
l2 = [elem for i, elem in enumerate(l1) if i not in toDelete]
now that I understand the question
a = numpy.array(list2)
mask = [True]*len(a)
mask[list1] = False
print a[mask]
Ok, this a slightly over-engineered solution, but here it is
def get_newl(li, index):
index = sorted(index, reverse=True)
i=0
while i < (len(li)-len(index)):
x = index.pop()
while i < x:
yield li[i]
i+=1
i+=1
Run the code here http://codebunk.com/bunk#-Isxeb4TZOHBCvQi4EsY

Searching List of Tuples by nth element in Python

So I have a list of tuples, with 3 elements each. Both the second and third elements are ints. For a value n, I need to return all the tuples that contain n as either the second or third element.
I'm not entirely sure how to do this, unfortunately. I'm sure it's not too complicated, but although there are some similar questions, I can't find any for this exact problem. Does anyone know how to go about this?
Thanks
You should be able to do this with a simple list comprehension. Something like:
[t for t in list_of_tuples if t[1] == n or t[2] == n]
Use a list comprehension with a simple if condition:
>>> lis=[('a',1,2),('b',2,2),('c',3,3),('d',3,1)]
>>> n=1
>>> [x for x in lis if n in x[1:3]] #[1:3] returns a sublist containing
# 2 & 3 element of each tuple
[('a', 1, 2), ('d', 3, 1)]
blist = [tup for tup in alist if n in tup[1:]]
The line above uses a list comprehension, and is equivalent to:
blist = []
for tup in alist:
if n in tup[1:]:
blist.append(tup)
tup[1:] returns a new tuple, consisting of the second and third items in the three item tuple tup.
In hindsight James Henstridge's example seems preferable, because t[1] == n or t[2] == n uses the existing tuple.

Categories

Resources