I am using Python and I would like to check the location of a value in a list of lists against other indexes.
Like if I had 1 at (1, 1) I would want to be able to check if 1 were at the other indexes so I could make something happen based on which index it matched.
For example:
list_of_lists = [
[4, 5, 6],
[7, 1, 8],
[6, 2, 9]
]
if 1 in row for row in list_of_lists:
if index of 1 is (0, 0), (0, 1), or (0, 2)
print ("It is in the First row!")
if index of 1 is (1, 0), (1, 1), or (1, 2)
print ("It is in the second row!")
If this worked correctly it should print: "It is in the second row!" Because the index of 1 matches with one of the indices in the third if statement. They may not necessarily be rows in some instances where I would be using this. So If you could provide a way that would not use the rows in your answer. Just a way to look at indexes and compare them. Obviously this is not the correct syntax. But how would I do that in Python? How would I get the index of 1 and compare it to other indexes in a list of lists?
Thanks!
trying this in a python file:
list_of_lists = [
[4, 5, 6],
[7, 0, 8],
[6, 2, 9]
]
def index_of(value, matrix):
for i, r in enumerate(matrix):
for j, c in enumerate(r):
if c == value:
# returns the first instance
return (i,j)
return None
if index_of(0, list_of_lists) == (1,1):
print "hey"
list_of_lists2 = [
[0, 5, 6],
[7, 0, 8],
[0, 2, 9]
]
def indexes_of(value, matrix):
return [(i,j) for i, r in enumerate(matrix) for j, c in enumerate(r) if c == value]
print indexes_of(0, list_of_lists2)
outputs
hey
[(0, 0), (1, 1), (2, 0)]
[EDIT] As requested:
First of all, what does enumerate do?
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
source
As you can see, if you use enumerate, it will return both the index of the element AND the element. Therefore, while you're iterating over the returned list you can access them and do what you desire. That's what I'm doing here:
for i, r in enumerate(matrix)
In that case, i stands for the row index, and r stands for row itself. ok?
In the next line you do the same thing, but now you're enumerating the row itself, ok? And you're getting, now, the indexes of the values j and the values c that are stored in each row.
Finally, when you return (i,j), you're just returning a tuple that represents the values's matrix index.
Here's one way to do it:
>>> for lst in range(len(list_of_lists)):
... if 1 in list_of_lists[lst]:
... print "it's in list:", lst
...
it's in list: 1
>>>
remember the in operator tests whether a value appears in a list (or list like object).
Here's a second way using the index method (discussed in the comments);
>>> for lst in range(len(list_of_lists)):
... try:
... _ = list_of_lists[lst].index(1)
... print "1 is in list", lst
... except ValueError:
... continue
...
1 is in list 1
>>>
Something like this:
def lindex(list_of_lists, item):
for l in list_of_lists:
if item in l:
return list_of_lists.index(l)
listoflists = [[4, 5, 6], [7, 1, 8], [6, 2, 9]]
item = 1
print "it is in the %. row" % lindex(listoflists, item)
As for your attempt to shortcut with:
if 1 in row for row in list_of_lists:
The syntax is incorrect!
You can't avoid to look into every item of every row of the list - NO shortcut
For a halway valid compromise to 1. you could try something like:
rows = [i for i in listoflists if 1 in i]
This would at either give you an empty list, meaning there are no items with the value "1" or a list the rows containing "1"!
You could then print all row-indices containing 1 with:
for row in rows:
print "it is in the %. row" % listoflists.index(row)
for i,list in enumerate(list_of_lists, 1):
if 1 in list:
if i == 1:
"it is in the first list"
elif i == 2:
"it is in the second list"
...
This is a basic implementation. You would want to parameterize this but I'm not sure exactly what your inputs would be.
Related
I'm trying to add values to an empty 2d list with this code:
values_to_go = [(7, 6, 2, 2, 350.0, '6', '11/05/2022\n', 7), (8, 6, 2, 1, 350.0, '08:30-10:30\n', '15/06/2022\n', 7), (9, 6, 2, 1, 350.0, '16:00-18:00\n', '25/08/2022\n', 7)]
list = []
for i in range(len(values_to_go)):
list[i][0] = values_to_go[i][0]
list[i][1] = values_to_go[i][5]
list[i][2] = values_to_go[i][6]
list[i][3] = values_to_go[i][2]
print(list)
But I'm getting this error:
TypeError: 'int' object is not subscriptable
Expected output: values_to_go = [(7, 6, 11/05/2022\n, 2), (8, 08:30-10:30\n, 15/06/2022\n, 2), (9, 16:00-18:00\n, 25/08/2022\n, 2)]
You have many mistakes in this code.
The values_to_go list is not a 2d list. The (7) or any number between parentheses is totally equal to a number without any parentheses. If you want to make it a tuple, you should tell python that these are not parentheses around the number; but these are tuple signs. So 7 is totally equal to (7). You should use (7,) to tell python that this is a tuple with one member which is 7. So this ... = values_to_go[i][0] will be OK.
Another mistake is the part that you've written to append members into the empty list. You cannot point to a non-existent member of a list with this expression: list[i][0]. There is no list[i] and therefore obviously there is no list[i][0]. If you want to append into the end of the list, you should just do it:
list.append(anything)
This would be something like this:
>>> values_to_go = [(7,), (8,), (9,)] # or [[7], [8], [9]]
>>> some_list = []
>>> for i in range(len(values_to_go)):
... some_list.append(values_to_go[i][0])
...
>>> print(some_list)
[7, 8, 9]
>>> # and if you want to make it 2D:
>>> some_list = []
>>> for i in range(len(values_to_go)):
... some_list.append([values_to_go[i][0]])
...
>>> print(some_list)
[[7], [8], [9]]
When you create your list, it is empty, so basically you can't access any position of it, first you have to create them you can do this with the .append() function.
Your code could look like this:
mylist = [[],[],[]]
for i in range(len(values_to_go)):
mylist[i].append(values_to_go[i][0])
mylist[i].append(values_to_go[i][5])
mylist[i].append(values_to_go[i][6])
mylist[i].append(values_to_go[i][2])
output: [[7, '6', '11/05/2022\n', 2], [8, '08:30-10:30\n', '15/06/2022\n', 2], [9, '16:00-18:00\n', '25/08/2022\n', 2], ]
Some extra tip, list is a Python reserved word, so don't use it as a variable name
Really not sure where this fits. Say, I have a list:
>>>a = [1, 2, 3, 4, 5, 6, 7]
How can I iterate it in such a way, that it will check 4 first, then 5, then 3, then 6, and then 2(and so on for bigger lists)? I have only been able to work out the middle which is
>>>middle = [len(a)/2 if len(a) % 2 = 0 else ((len(a)+1)/2)]
I'm really not sure how to apply this, nor am I sure that my way of working out the middle is the best way. I've thought of grabbing two indexes and after each iteration, adding 1 and subtracting 1 from each respective index but have no idea how to make a for loop abide by these rules.
With regards as to why I need this; it's for analysing a valid play in a card game and will check from the middle card of a given hand up to each end until a valid card can be played.
You can just keep removing from the middle of list:
lst = range(1, 8)
while lst:
print lst.pop(len(lst)/2)
This is not the best solution performance-wise (removing item from list is expensive), but it is simple - good enough for a simple game.
EDIT:
More performance stable solution would be a generator, that calculates element position:
def iter_from_middle(lst):
try:
middle = len(lst)/2
yield lst[middle]
for shift in range(1, middle+1):
# order is important!
yield lst[middle - shift]
yield lst[middle + shift]
except IndexError: # occures on lst[len(lst)] or for empty list
raise StopIteration
To begin with, here is a very useful general purpose utility to interleave two sequences:
def imerge(a, b):
for i, j in itertools.izip_longest(a,b):
yield i
if j is not None:
yield j
with that, you just need to imerge
a[len(a) / 2: ]
with
reversed(a[: len(a) / 2])
You could also play index games, for example:
>>> a = [1, 2, 3, 4, 5, 6, 7]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1]
>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1, 8]
Here's a generator that yields alternating indexes for any given provided length. It could probably be improved/shorter, but it works.
def backNforth(length):
if length == 0:
return
else:
middle = length//2
yield middle
for ind in range(1, middle + 1):
if length > (2 * ind - 1):
yield middle - ind
if length > (2 * ind):
yield middle + ind
# for testing:
if __name__ == '__main__':
r = range(9)
for _ in backNforth(len(r)):
print(r[_])
Using that, you can just do this to produce a list of items in the order you want:
a = [1, 2, 3, 4, 5, 6, 7]
a_prime = [a[_] for _ in backNforth(len(a))]
In addition to the middle elements, I needed their index as well. I found Wasowski's answer very helpful, and modified it:
def iter_from_middle(lst):
index = len(lst)//2
for i in range(len(lst)):
index = index+i*(-1)**i
yield index, lst[index]
>>> my_list = [10, 11, 12, 13, 14, 15]
>>> [(index, item) for index, item in iter_from_middle(my_list)]
[(3, 13), (2, 12), (4, 14), (1, 11), (5, 15), (0, 10)]
I want to write a search function that takes in a value x and a sorted sequence and returns the position that the value should go to by iterating through the elements of the sequence starting from the first element. The position that x should go to in the list should be the first position such that it will be less than or equal to the next element in the list.
Example:>>> search(-5, (1, 5, 10))——0
>>> search(3, (1, 5, 10))——1
Building a list of every item would be a bit of a waste of resources if there were big gaps in the list, instead you can just iterate through each list item until the input is bigger than the value.
In terms of your code -
def search(input,inputList):
for i in range( len( inputList ) ):
if inputList[i]>input:
return i
return len( inputList )
print search(-5, (1, 5, 10))
#Result: 0
print search(3, (1, 5, 10))
#Result: 1
To insert it into the list, this would work, I split the list in 2 based on the index and add the value in the middle.
def insert(input,inputList):
index = search(input,inputList) #Get where the value should be inserted
newInput = [input]+list(inputList[index:]) #Add the end of the list to the input
if index:
newInput = list(inputList[:index])+newInput #Add the start of the list if the index isn't 0
return newInput
print insert(-5, (1, 5, 10))
#Result: (-5, 1, 5, 10)
print insert(3, (1, 5, 10))
#Result: (1, 3, 5, 10)
since someone has answered a similar question, I will just draw a rough skeleton of what u may want to do.
declare a list and populate it with your stuff;
mylist = [1, 2, 3, 5, 5, 6, 7]
then just make a function and iterate the list;
def my_func( x, mylist):
for i in mylist:
if((mylist[i] == x)|| (mylist[i] > x)):
return i
Given 3 in list (1, 2, 3, 4, 5), the function should return index 2.
Given 3 in list (1, 2, 4, 5, 6), it should still return 2
You may want to check my python code, because I have not checked this for errors, I am assuming you know some python and if you have the skeleton, you should crack it. And Oh, python cares about the tabbibg I did.
Im trying to write a function that creates set of dynamic sublists each containing 5 elements from a list passed to it.Here's my attempt at the code
def sublists(seq):
i=0
x=[]
while i<len(seq)-1:
j=0
while j<5:
X.append(seq[i]) # How do I change X after it reaches size 5?
#return set of sublists
EDIT:
Sample input: [1,2,3,4,5,6,7,8,9,10]
Expected output: [[1,2,3,4,5],[6,7,8,9,10]]
Well, for starters, you'll need to (or at least should) have two lists, a temporary one and a permanent one that you return (Also you will need to increase j and i or, more practically, use a for loop, but I assume you just forgot to post that).
EDIT removed first code as the style given doesn't match easily with the expected results, see other two possibilities.
Or, more sensibly:
def sublists(seq):
x=[]
for i in range(0,len(seq),5):
x.append(seq[i:i+5])
return x
Or, more sensibly again, a simple list comprehension:
def sublists(seq):
return [seq[i:i+5] for i in range(0,len(seq),5)]
When given the list:
l = [1,2,3,4,5,6,7,8,9,10]
They will return
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
Have you considered using itertools.combinations(...)?
For example:
>>> from itertools import combinations
>>> l = [1,2,3,4,5,6]
>>> list(combinations(l, 5))
[(1, 2, 3, 4, 5), (1, 2, 3, 4, 6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
By "dynamic sublists", do you mean break up the list into groups of five elements? This is similar to your approach:
def sublists(lst, n):
ret = []
i = 0
while i < len(lst):
ret.append(seq[i:i+n])
i += n
return ret
Or, using iterators:
def sublists(seq, n):
it = iter(seq)
while True:
r = list(itertools.islice(it, 5))
if not r:
break
yield r
which will return an iterator of lists over list of length up to five. (If you took out the list call, weird things would happen if you didn't access the iterators in the same order.)
Python's list type has an index() method that takes one parameter and returns the index of the first item in the list matching the parameter. For instance:
>>> some_list = ["apple", "pear", "banana", "grape"]
>>> some_list.index("pear")
1
>>> some_list.index("grape")
3
Is there a graceful (idiomatic) way to extend this to lists of complex objects, like tuples? Ideally, I'd like to be able to do something like this:
>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> some_list.getIndexOfTuple(1, 7)
1
>>> some_list.getIndexOfTuple(0, "kumquat")
2
getIndexOfTuple() is just a hypothetical method that accepts a sub-index and a value, and then returns the index of the list item with the given value at that sub-index. I hope
Is there some way to achieve that general result, using list comprehensions or lambas or something "in-line" like that? I think I could write my own class and method, but I don't want to reinvent the wheel if Python already has a way to do it.
How about this?
>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> [x for x, y in enumerate(tuple_list) if y[1] == 7]
[1]
>>> [x for x, y in enumerate(tuple_list) if y[0] == 'kumquat']
[2]
As pointed out in the comments, this would get all matches. To just get the first one, you can do:
>>> [y[0] for y in tuple_list].index('kumquat')
2
There is a good discussion in the comments as to the speed difference between all the solutions posted. I may be a little biased but I would personally stick to a one-liner as the speed we're talking about is pretty insignificant versus creating functions and importing modules for this problem, but if you are planning on doing this to a very large amount of elements you might want to look at the other answers provided, as they are faster than what I provided.
Those list comprehensions are messy after a while.
I like this Pythonic approach:
from operator import itemgetter
tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
def collect(l, index):
return map(itemgetter(index), l)
# And now you can write this:
collect(tuple_list,0).index("cherry") # = 1
collect(tuple_list,1).index("3") # = 2
If you need your code to be all super performant:
# Stops iterating through the list as soon as it finds the value
def getIndexOfTuple(l, index, value):
for pos,t in enumerate(l):
if t[index] == value:
return pos
# Matches behavior of list.index
raise ValueError("list.index(x): x not in list")
getIndexOfTuple(tuple_list, 0, "cherry") # = 1
One possibility is to use the itemgetter function from the operator module:
import operator
f = operator.itemgetter(0)
print map(f, tuple_list).index("cherry") # yields 1
The call to itemgetter returns a function that will do the equivalent of foo[0] for anything passed to it. Using map, you then apply that function to each tuple, extracting the info into a new list, on which you then call index as normal.
map(f, tuple_list)
is equivalent to:
[f(tuple_list[0]), f(tuple_list[1]), ...etc]
which in turn is equivalent to:
[tuple_list[0][0], tuple_list[1][0], tuple_list[2][0]]
which gives:
["pineapple", "cherry", ...etc]
You can do this with a list comprehension and index()
tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
[x[0] for x in tuple_list].index("kumquat")
2
[x[1] for x in tuple_list].index(7)
1
Inspired by this question, I found this quite elegant:
>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> next(i for i, t in enumerate(tuple_list) if t[1] == 7)
1
>>> next(i for i, t in enumerate(tuple_list) if t[0] == "kumquat")
2
I would place this as a comment to Triptych, but I can't comment yet due to lack of rating:
Using the enumerator method to match on sub-indices in a list of tuples.
e.g.
li = [(1,2,3,4), (11,22,33,44), (111,222,333,444), ('a','b','c','d'),
('aa','bb','cc','dd'), ('aaa','bbb','ccc','ddd')]
# want pos of item having [22,44] in positions 1 and 3:
def getIndexOfTupleWithIndices(li, indices, vals):
# if index is a tuple of subindices to match against:
for pos,k in enumerate(li):
match = True
for i in indices:
if k[i] != vals[i]:
match = False
break;
if (match):
return pos
# Matches behavior of list.index
raise ValueError("list.index(x): x not in list")
idx = [1,3]
vals = [22,44]
print getIndexOfTupleWithIndices(li,idx,vals) # = 1
idx = [0,1]
vals = ['a','b']
print getIndexOfTupleWithIndices(li,idx,vals) # = 3
idx = [2,1]
vals = ['cc','bb']
print getIndexOfTupleWithIndices(li,idx,vals) # = 4
ok, it might be a mistake in vals(j), the correction is:
def getIndex(li,indices,vals):
for pos,k in enumerate(lista):
match = True
for i in indices:
if k[i] != vals[indices.index(i)]:
match = False
break
if(match):
return pos
z = list(zip(*tuple_list))
z[1][z[0].index('persimon')]
tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
def eachtuple(tupple, pos1, val):
for e in tupple:
if e == val:
return True
for e in tuple_list:
if eachtuple(e, 1, 7) is True:
print tuple_list.index(e)
for e in tuple_list:
if eachtuple(e, 0, "kumquat") is True:
print tuple_list.index(e)
Python's list.index(x) returns index of the first occurrence of x in the list. So we can pass objects returned by list compression to get their index.
>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> [tuple_list.index(t) for t in tuple_list if t[1] == 7]
[1]
>>> [tuple_list.index(t) for t in tuple_list if t[0] == 'kumquat']
[2]
With the same line, we can also get the list of index in case there are multiple matched elements.
>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11), ("banana", 7)]
>>> [tuple_list.index(t) for t in tuple_list if t[1] == 7]
[1, 4]
I guess the following is not the best way to do it (speed and elegance concerns) but well, it could help :
from collections import OrderedDict as od
t = [('pineapple', 5), ('cherry', 7), ('kumquat', 3), ('plum', 11)]
list(od(t).keys()).index('kumquat')
2
list(od(t).values()).index(7)
7
# bonus :
od(t)['kumquat']
3
list of tuples with 2 members can be converted to ordered dict directly, data structures are actually the same, so we can use dict method on the fly.
This is also possible using Lambda expressions:
l = [('rana', 1, 1), ('pato', 1, 1), ('perro', 1, 1)]
map(lambda x:x[0], l).index("pato") # returns 1
Edit to add examples:
l=[['rana', 1, 1], ['pato', 2, 1], ['perro', 1, 1], ['pato', 2, 2], ['pato', 2, 2]]
extract all items by condition:
filter(lambda x:x[0]=="pato", l) #[['pato', 2, 1], ['pato', 2, 2], ['pato', 2, 2]]
extract all items by condition with index:
>>> filter(lambda x:x[1][0]=="pato", enumerate(l))
[(1, ['pato', 2, 1]), (3, ['pato', 2, 2]), (4, ['pato', 2, 2])]
>>> map(lambda x:x[1],_)
[['pato', 2, 1], ['pato', 2, 2], ['pato', 2, 2]]
Note: The _ variable only works in the interactive interpreter. More generally, one must explicitly assign _, i.e. _=filter(lambda x:x[1][0]=="pato", enumerate(l)).
I came up with a quick and dirty approach using max and lambda.
>>> tuple_list = [("pineapple", 5), ("cherry", 7), ("kumquat", 3), ("plum", 11)]
>>> target = 7
>>> max(range(len(tuple_list)), key=lambda i: tuple_list[i][1] == target)
1
There is a caveat though that if the list does not contain the target, the returned index will be 0, which could be misleading.
>>> target = -1
>>> max(range(len(tuple_list)), key=lambda i: tuple_list[i][1] == target)
0