I have two lists. The first is a_list and is like this:
a_list = [1,2,3]
The second is b_list, and it's a list with lists in it. It's like this:
b_list = [['a',1,'b'],['c',2,'g'],['e',3,'5']
What I'm trying to do is use a_list to find the correct b_list and print the value[2] in the b_list.
My code looks like:
for a in a_list:
for b in b_list:
if b[1] == a:
print b[2]
The actually a_list has 136 values in it. And the real b_list has 315 lists in it.
I had initially written code to index the b item and remove it from b_list if b[1] == a.
I've taken that code out in order to solve the real problem.
There is no need to loop over a_list; a simple in test would suffice:
for b in b_list:
if b[1] in a_list:
print b[2]
This would perform better if you made a_list a set:
a_set = set(a_list)
for b in b_list:
if b[1] in a_set:
print b[2]
Either way, this code prints:
b
g
5
for your example data.
If I understood correctly what you want to do:
a_list = [1,2,3,5]
b_list = [['a',1,'b'],['c',2,'g'],['e',3,'5'],
['d',4,'h'],['Z',5,'X'],['m',6,'i']]
print 'a_list ==',a_list
print '\nb_list before :\n',b_list
print '\nEnumerating b_list in reversed order :'
L = len(b_list)
print (' i el L-i b_list[L-i] \n'
' -------------------------------------')
for i,el in enumerate(b_list[::-1],1):
print ' %d %r %d %r' % (i,el,L-i,b_list[L-i])
L = len(b_list)
for i,el in enumerate(b_list[::-1],1):
if el[1] in a_list:
del b_list[L-i]
print '\nb_list after :\n',b_list
result
a_list == [1, 2, 3, 5]
b_list before :
[['a', 1, 'b'], ['c', 2, 'g'], ['e', 3, '5'],
['d', 4, 'h'], ['Z', 5, 'X'], ['m', 6, 'i']]
Enumerating b_list in reversed order :
i el L-i b_list[L-i]
-------------------------------------
1 ['m', 6, 'i'] 5 ['m', 6, 'i']
2 ['Z', 5, 'X'] 4 ['Z', 5, 'X']
3 ['d', 4, 'h'] 3 ['d', 4, 'h']
4 ['e', 3, '5'] 2 ['e', 3, '5']
5 ['c', 2, 'g'] 1 ['c', 2, 'g']
6 ['a', 1, 'b'] 0 ['a', 1, 'b']
b_list after :
[['d', 4, 'h'], ['m', 6, 'i']]
The reason why it is necessary to iterate in b_list in reversed order is the one said by abarnert and explained hereafter by the doc:
Note: There is a subtlety when the sequence is being modified by the
loop (this can only occur for mutable sequences, i.e. lists). An
internal counter is used to keep track of which item is used next, and
this is incremented on each iteration. When this counter has reached
the length of the sequence the loop terminates. This means that if the
suite deletes the current (or a previous) item from the sequence, the
next item will be skipped (since it gets the index of the current item
which has already been treated). Likewise, if the suite inserts an
item in the sequence before the current item, the current item will be
treated again the next time through the loop. This can lead to nasty
bugs that can be avoided by making a temporary copy using a slice of
the whole sequence, e.g.,
for x in a[:]:
if x < 0: a.remove(x)
http://docs.python.org/2/reference/compound_stmts.html#the-for-statement
Related
I have two arrays:
a = np.array([1,3,4,2,6])
b = np.array(['c', 'd', 'e', 'f', 'g'])
These two array are linked (in the sense that there is a 1-1 correspondence between the elements of the two arrays), so when i sort a by decreasing order I would like to sort b in the same order.
For instance, when I do:
a = np.sort(a)[::-1]
I get:
a = [6, 4, 3, 2, 1]
and I would like to be able to get also:
b = ['g', 'e', 'd', 'f', 'c']
i would do smth like this:
import numpy as np
a = np.array([1,3,4,2,6])
b = np.array(['c', 'd', 'e', 'f', 'g'])
idx_order = np.argsort(a)[::-1]
a = a[idx_order]
b = b[idx_order]
output:
a = [6 4 3 2 1]
b = ['g' 'e' 'd' 'f' 'c']
I don't know how or even if you can do this in numpy arrays. However there is a way using standard lists albeit slightly convoluted. Consider this:-
a = [1, 3, 4, 2, 6]
b = ['c', 'd', 'e', 'f', 'g']
assert len(a) == len(b)
c = []
for i in range(len(a)):
c.append((a[i], b[i]))
r = sorted(c)
for i in range(len(r)):
a[i], b[i] = r[i]
print(a)
print(b)
In your problem statement, there is no relationship between the two tables. What happens here is that we make a relationship by grouping relevant data from each table into a temporary list of tuples. In this scenario, sorted() will carry out an ascending sort on the first element of each tuple. We then just rebuild our original arrays
Consider the following example:
list1 = [[A,B,C,D],[A,B,C,D],[A,B,C,D]]
list2 = [[B,C],[B,C],[B,C]]
I want to create a new list of items in list 1 that match B,C from both lists. For example:
list1 = [[1,A,B,2],[1,D,E,3],[2,F,G,4]]
list2 = [[A,B],[B,C],[F,G]]
So after matching the above I want the result to be:
newlst = [[1,A,B,2],[2,F,G,4]]
I attempted to use a for loop and where row[1] in list2 but that didnt work. I also tried:
match = set(list1) & set(list2)
That did not work either.
I have no idea where you were going with your set approach. Since & is a bitwise operator. But what you want to do is loop over list 1 and check if the 2nd and 3rd element matches any in list 2.
This can be done in one line via list comprehension.
newlst = [i for i in list1 if i[1:3] in list2]
This is equivalent to-
newlst = []
#loop over list1
for i in list1:
#i[1:3] returns a list of 2nd and 3rd element
#if the 2nd and 3rd element are in the second list
if i[1:3] in list2:
newlst.append(i)
This looks like it gives what you want:
list1 = [[1, 'A', 'B' ,2], [1, 'D', 'E',3], [2, 'F', 'G', 4]]
list2 = [['A', 'B'], ['B', 'C'], ['F', 'G']]
list3 = [e for (e, k) in zip(list1, list2) if (e[1] == k[0] and e[2] == k[1])]
list3
[[1, 'A', 'B', 2], [2, 'F', 'G', 4]]
This question already has answers here:
Listing words randomly without repeating them
(2 answers)
Closed 1 year ago.
I am a complete amateur and know there probably is easier ways to do this, but this isn't an important project, just a superquick code. For some reason it seems like it gets stuck in a loop because random.choice gives the same number over and over again. It works sometimes, I just have to give it a couple of tries, and as I increase the range the more difficult it is.
The code is supposed to allocate a unique number to each "player" every round, without giving the same player the same number twice.
import random
A = []
B = []
C = []
D = []
E = []
F = []
G = []
H = []
I = []
J = []
K = []
lt = [A, B, C, D, E, F, G, H, I, J, K]
lit = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
ALT = 0
for e in range(5):
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
for i in lt:
while True:
add = random.choice(lst)
if add not in i:
i.append(add)
lst.remove(add)
break
else:
print('fant ingenting')
ALT += 1
print(ALT)
tot = 0
for k in lt:
print(str(lit[tot]) + ' = ' + str(k))
tot += 1
So you have a list of 11 players and you want to assign 11 unique IDs (from 1 to 11) to them. Why not just shuffle() the list of IDs once and be done with it?
lit = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
random.shuffle(lst)
for player, player_id in zip(lit, lst):
print("player", player, "has id", player_id)
If you want to give random IDs multiple times without repeating, a very simple way to do this would be to just rotate them:
lit = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
random.shuffle(lst)
for round in range(5):
print("Round", round)
for player, player_id in zip(lit, lst):
print("> player", player, "has id", player_id)
lst = lst[1:] + lst[:1]
Note that that last step of rotating using lst = lst[1:] + lst[:1] is ok with small lists, but can be really inefficient for large lists, since it creates a new copy of the entire list every time. If you are working with larger lists, you can use a deque:
lit = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
random.shuffle(lst)
lst = deque(lst)
for round in range(5):
print("Round", round)
for player, player_id in zip(lit, lst):
print("> player", player, "has id", player_id)
lst.rotate(1)
One caveat of this solution is that since players are ordered, the IDs will be distributed each round in order. So, for example, you already know that if the IDs are initially 1, 2, 3 for players A, B, C the player C will get IDs 2 and 1 in the next two rounds. In order to avoid this and get more unpredictable IDs you could also shuffle the list of players first:
random.shuffle(lit)
random.shuffle(lst)
# ... same code as above ...
This way you will not have a predictable "next player" to get a specific ID.
I have a list of list as follows:
list_1 = [[[1,a],[2,b]], [[3,c],[4,d]], [[1,a],[5,d]], [[8,r],[10,u]]]
I am trying to find whether an element is this list is similar to another element. Right now, I'm looping it twice i.e. for each element, check against the rest. My output is:
[[[1,a],[2,b]], [[1,a],[5,d]]]
Is there a way to do this more efficiently?
Thanks.
You can use itertools.combinations and any functions like this
from itertools import combinations
for item in combinations(list_1, 2):
if any(i in item[1] for i in item[0]):
print item
Output
([[1, 'a'], [2, 'b']], [[1, 'a'], [5, 'd']])
I'm assuming that, by similar, you mean that the element has at least one matching pair within it. In this case, rather than do a nested loop, you could map each element into a dict of lists twice (once for each [number,str] pair within it). When you finish, each key in the dict will map to the list of elements which contain that key (i.e., are similar).
Example code:
list_1 = [[[1,'a'],[2,'b']], [[3,'c'],[4,'d']], [[1,'a'],[5,'d']], [[8,'r'],[10,'u']]]
d = {}
for elt in list_1:
s0 = '%d%s' % (elt[0][0], elt[0][1])
if s0 in d:
d[s0].append(elt)
else:
d[s0] = [elt]
s1 = '%d%s' % (elt[1][0], elt[1][1])
if s1 in d:
d[s1].append(elt)
else:
d[s1] = [elt]
for key in d.keys():
print key, ':', d[key]
Example output:
1a : [[[1, 'a'], [2, 'b']], [[1, 'a'], [5, 'd']]]
8r : [[[8, 'r'], [10, 'u']]]
2b : [[[1, 'a'], [2, 'b']]]
3c : [[[3, 'c'], [4, 'd']]]
5d : [[[1, 'a'], [5, 'd']]]
4d : [[[3, 'c'], [4, 'd']]]
10u : [[[8, 'r'], [10, 'u']]]
Any of the dict entries with length > 1 have similar elements. This will reduce the runtime complexity of your code to O(n), assuming you have a way to obtain a string representation of a, b, c, etc.
How do I delete a "column" from a list of lists?
Given:
L = [
["a","b","C","d"],
[ 1, 2, 3, 4 ],
["w","x","y","z"]
]
I would like to delete "column" 2 to get:
L = [
["a","b","d"],
[ 1, 2, 4 ],
["w","x","z"]
]
Is there a slice or del method that will do that? Something like:
del L[:][2]
You could loop.
for x in L:
del x[2]
If you're dealing with a lot of data, you can use a library that support sophisticated slicing like that. However, a simple list of lists doesn't slice.
just iterate through that list and delete the index which you want to delete.
for example
for sublist in list:
del sublist[index]
You can do it with a list comprehension:
>>> removed = [ l.pop(2) for l in L ]
>>> print L
[['a', 'b', 'd'], [1, 2, 4], ['w', 'x', 'z']]
>>> print removed
['d', 4, 'z']
It loops the list and pops every element in position 2.
You have got list of elements removed and the main list without these elements.
A slightly twisted version:
index = 2 # Delete column 2
[(x[0:index] + x[index+1:]) for x in L]
[(x[0], x[1], x[3]) for x in L]
It works fine.
This is a very easy way to remove whatever column you want.
L = [
["a","b","C","d"],
[ 1, 2, 3, 4 ],
["w","x","y","z"]
]
temp = [[x[0],x[1],x[3]] for x in L] #x[column that you do not want to remove]
print temp
O/P->[['a', 'b', 'd'], [1, 2, 4], ['w', 'x', 'z']]
L = [['a', 'b', 'C', 'd'], [1, 2, 3, 4], ['w', 'x', 'y', 'z']]
_ = [i.remove(i[2]) for i in L]
If you don't mind on creating new list then you can try the following:
filter_col = lambda lVals, iCol: [[x for i,x in enumerate(row) if i!=iCol] for row in lVals]
filter_out(L, 2)
An alternative to pop():
[x.__delitem__(n) for x in L]
Here n is the index of the elements to be deleted.