Check indexes against lists with indexes - python

If I have a list of lists in Python, and I make lists from parts of that list of lists, how could I check which list an index were in.
For example:
LOL = [
[4, 5, 6],
[7, 1, 8],
[6, 2, 9]
]
list1 = [LOL[0][0], LOL[0][1], LOL[1][1]]
list2 = [LOL[2][2], LOL[2][1], LOL[1][2]]
list3 = [LOL[2][0], LOL[1][2], LOL[0][2]]
(These indices are completely intentional.) The 1 in this list of lists (LOL) is at index LOL[1][1] (1,1). How would I check which out of the three lists: list1, list2, and/or list3, it is in?
if 1 in row for row in LOL:
(search the list that the 1 is in for 6. The integers contained in the lists in LOL are just examples, there could be multiple 1's in the lists in LOL.)
If there was actual Python Syntax inside the parenthesis that would accomplish the described task, list1 would be searched and because there aren't any 6's in that list the if statement would fall through. How would I fill in the part in parenthesis so that it had the correct Python syntax to accomplish the task described there?

There are two many issues with the question, and too many comments, so I'm putting the following in an answer:
Firstly, in
list1 = [LOL[0][0], LOL[0][1], LOL[1][1]]
list2 = [LOL[2][2], LOL[2][1], LOL[1][2]]
list3 = [LOL[2][0], LOL[1][2], LOL[0][2]]
Are the indices correct? Or should they be
list1 = [LOL[0][0], LOL[0][1], LOL[0][2]]
list2 = [LOL[1][0], LOL[1][1], LOL[1][2]]
list3 = [LOL[2][0], LOL[2][1], LOL[2][2]]
Secondly,
The one in this list of lists is at index LOL[1][1].
This statement does not make sense. By 'one' you are referring to '1', which is at 'index' (1,1) in the sense that LOL[1][1] contains '1'. LOL[1][1] is not an index, it is a value (in fact, it refers to a value).
How would I check which list it is in?
Which list are you talking about? The list1, list2 or list3 (ie, find in which of those 3 the '1' is referenced), or LOL[0], LOL[1], LOL[2] (ie find in which 'row' is '1' referenced)? Because LOL contains 3 items, each one a list (of integers). LOL does not contain any integers (the items in LOL contain integers).
For this reason,
if 1 in LOL:
is not valid Python: LOL does not contain any integers. It does make sense if it is pseudocode.
Another issue:
(search the list that the 1 is in for 0.
0 is not in any list, this is confusing, is it a typo?
LOL is just an example there could be multiple ones.)
Multiple LOL? How is the fact that there are multiple LOL relevant to the task of finding something in LOL? Or perhaps what you really have is this:
list1 = [LOL2[1][2], LOL1[0][2], LOL3[2][2]]
list2 = [LOL2[1][2], LOL2[0][2], LOL0[2][2]]
list3 = [LOL1[1][2], LOL0[0][2], LOL3[0][2]]
where I picked the LOL0/1/2/3 randomly as an example. In this case what you are trying to solve is, if you find that '1' is in LOL2, at what (row, col) index is it in LOL2? The row col will satsify LOL2[row][col] is '1'. But this doesn't make much sense to me either.
Finally, if you could provide an example answer like "and the answer would be list2" or "and the answer would be LOL[1]", that can help a lot with understanding what you are trying to achieve.
Please clarify your post with all of the above to minimize how much back and forth commenting occurs, there is a huge amount of noise right now and I'm really tempted to flag the question for closure so you can start from scratch (I feel it is a good question so I hope to see it through).

The list1, 2 and 3 do not contain references to the numbers in the LOL. Consider this:
Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> ll=[1,2,3]
>>> kk=[ll[1], ll[0], ll[2]]
>>> kk
[2, 1, 3]
>>> ll[2]=5
>>> kk
[2, 1, 3]
>>>
So the code you show, once executed, causes the following to be in Python interpreter:
LOL = [
[4, 5, 6],
[7, 1, 8],
[6, 2, 9]
]
list1 = [4, 5, 1]
list2 = [9, 2, 8]
list3 = [6, 8, 6]
Ie, there are no references to numbers, just the numbers themselves.
Since 1 is unique you could find by element search which list1/2/3 it is in, but for a number like 8, there would be two answers (list2 and list3). Also, there is no way of knowing, as shown in my first code sample, which LOL item the number corresponds to: is list3[0] the LOL[0][2] or the LOL[2][0]? There is no way of knowing.
OTOH, if you store objects in your LOL lists instead of numbers, you can find them by reference. Consider this code:
>>> a,b,c=[0],[1],[2]
>>> ll=[a,b,c]
>>> ll
[[0], [1], [2]]
>>> a[0]=5
>>> ll
[[5], [1], [2]]
>>>
This shows that ll is storing references to a, b, c, because those are themselves objects.
Then it is possible to find which of a,b,c contains a given number, and to find where the number is specifically in ll:
if 2 in a:
return ll.index(a)
if 2 in b:
return ll.index(b)
if 2 in c:
return ll.index(c)
Given the above, I suspect the answer is that you cannot get what you are looking for, unless you rewrite your LOL and 3 lists to contain objects, like this:
a,b,c,d,e,f,...=[0],[1],[2],[4],[2],[6],...
LOL=[[a,b,c],[d,e,f],[g,h,i]]
list1=[a,c,f]
list2=[d,a,b]
list3=[f,g,a]
Then if you are looking for c, which has same number as e but is a different object, you would do
index = getIndex(c[0], list1)
if index >= 0:
return getLOLItem(list1[index])
where
def getLOLItem(item):
for subLOL in LOL:
if item in subLOL:
return subLOL.index(item)

if 1 in some_list:
...
As for how to check the different variables, don't. Put them in a list or dict instead.

val = 1
for i, lst in enumerate(LOL):
if val in lst:
print(i, lst.index(val))
will print "1, 1".

Maybe this is what you want:
LOL = [[4, 5, 6],
[7, 1, 8],
[6, 2, 9] ]
list1 = [LOL[0][0], LOL[0][1], LOL[1][1]]
list2 = [LOL[2][2], LOL[2][1], LOL[1][2]]
list3 = [LOL[2][0], LOL[1][2], LOL[0][2]]
def sublist_index_of_li_in_which_is_x(li,x):
return (i for i,sublist in enumerate(li) if x in sublist).next()
print sublist_index_of_li_in_which_is_x(LOL,1)
print sublist_index_of_li_in_which_is_x(LOL,9)
return
1
2
Maybe.
By the way, what list1,list2,list3 are playing here ?
EDIT
def rowcol_tuples_locating_x_in_li(li,x):
return [(i,sublist.index(x)) for i,sublist in enumerate(li) if x in sublist]
print rowcol_tuples_locating_x_in_li(LOL,1)
print rowcol_tuples_locating_x_in_li(LOL,6)
result
[(1, 1)]
[(0, 2), (2, 0)]

It seems there is confusion in the use of "index" here. I'll take a stab at it. This will return the name of the sublist and the index within the sublist. I think others have shown how to find the index in the original LOL.
LOL = [
[4, 5, 6],
[7, 1, 8],
[6, 2, 9],
]
#store the sublists in a dictionary
checkLists = {
'list1':[LOL[0][0], LOL[0][1], LOL[1][1]],
'list2':[LOL[2][2], LOL[2][1], LOL[1][2]],
'list3':[LOL[2][0], LOL[1][2], LOL[0][2]]
}
#the value you are looking for
checkVal = 1
#recursive function to search for a value in a list of lists
def containsValue(val,items):
for item in items:
if isinstance(item,(list,tuple)):
if find(val,item):
return True
else:
print item
if item == val:
return True
return False
#Now check to see if and where the checkVal exists in the sublists
if containsValue(checkVal, LOL):
#search each sublist for the checkVal
for k,v in checkLists.items():
#see if the value is in the sublist
if checkVal in v:
#return the sublist key and index where we found the value
i = v.index(checkVal)
return (k,i)

Related

Python Check if a 2-dimensional list contains numbers of another list

I want to know if a list contains numbers from a list of a list, but nothing I tried worked as I wanted. For example if a list of a list in list2 = [[1,2,3],[4,5,6]] is in list1 = [4, 5, 6, 7] it should print out True, because the numbers of list1 are a whole list from list2. So because list1 contains the numbers 4, 5, 6 the output should be True.
Here is what I tried
for i in range(len(list2)):
if list1 in list2[i]:
print('True')
else:
print('False')
It prints out False two times (but I need it to print out True) and I get why
[1, 2, 3] in [1, 2, 3, 4]
>>> False
Is there a way to avoid this?
Or should I just use strings since it works with them just fine?
Finding if a collection of items is a subset of another is more efficiently handled by a set than a list. Casting your list to a set allow quick lookup with the set.issuperset method.
list_of_lists = [[1,2,3],[4,5,6]]
list1 = [4, 5, 6, 7]
list1_as_set = set(list1)
result = any(list1_as_set.issuperset(l) for l in list_of_lists) # True
The above code using any is equivalent to this solution using a for-loop.
for l in list_of_lists:
if list1_as_set.issuperset(l):
result = True
break
else:
result = False

Python Removing a sublist in a list without changing the index of other sublists in the list

Say for example:
list = { [1,2,3],[4,5,6],[3,4],[2,7,8,9] }
is there a way in python to remove a sublist and make sure that other sublists index's remain the same. So for example if i was to remove the sublist [3,4], could i make sure that the index of [2,7,8,9] remains as 3 in this case? if this is possible it would really be helpful! thanks!
Maybe. It depends on how you use the list and just how "listy" the resulting object needs to be.
l = [ [1,2,3],[4,5,6],[3,4],[2,7,8,9] ]
You could replace the sublist with something else like a None. Then your code would have to know to ignore None when it processes the list.
print(l[3])
l[2] = None
print(l[3])
or you could convert the list to a dict and delete the member. You can still index the object but since its now a dict, your code will have to treat it like a dict.
l = dict(enumerate(l))
print l[3]
del l[2]
print l[3]
These tricks will only work in some specialized environments.
You can just delete the elements in [3,4] and keep the empty sub-list.
>>> lst = [[1,2,3],[4,5,6],[3,4],[2,7,8,9]]
>>> del lst[2][:]
>>> lst
[[1, 2, 3], [4, 5, 6], [], [2, 7, 8, 9]]
Please note that you should not use list as a variable name as list is a built in function
But you can store the index with the value as a tuple. First make a modified list which has both index and value. Then you are free to remove any of the element.
lst = [[1,2,3],[4,5,6],[3,4],[2,7,8,9]]
modified = list(enumerate(lst))
To explain a bit:
modified=[]
for i,v in enumerate(lst):
modified.append((i,v))
print modified
Output:
[(0, [1, 2, 3]), (1, [4, 5, 6]), (2, [3, 4]), (3, [2, 7, 8, 9])]

How to pick the smallest value in a list when an iterative process is applied to the list

I need to find the smallest value in a series of lists. I understand the code for the smallest value in just one list:
>>> x = [1, 2, 3, 4, 5]
>>> print (min(x))
1
Simple enough. However, I would like to know if there is a way to write code that finds the smallest value for each list I have without stopping and adjusting the code (whether by an iterative process or some other means). Any help would be greatly appreciated. Thanks in advance!
First, make a list of lists out of your separate lists. For example, if you have lists A, B and C, the list of lists would be [A,B,C].
Now, to get a list of all the minimum values for each list in a list of lists lst:
[min(x) for x in lst]
To get the global minimum:
min(x for sublist in lst for x in sublist)
Demo:
>>> lst
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [min(x) for x in lst]
[1, 4, 7]
>>> min(x for sublist in lst for x in sublist)
1
Edit in reaction to OP's comment:
I just want the minimum value for each list. I don't need to compile all of the minimum values together into a new list
If you just want to print the minimum values for each list A, B, C, ... , you can do:
for lst in (A,B,C): # put as many lists as you like into the parentheses
print(min(lst))
Edit in reaction to
I am only accessing one list (in this case, the values are well depths) at a time. [..] What I would like to know is how to write a code that finds the smallest value in a list given that the iterator essentially changes the values in said list.
Just print(min(lst)) each time lst has changed.
Assuming you've got a list of lists, this should do it:
minimums = [min(l) for l in lists]

Concatenate List Object Name with a Number and Retain the List Python

I'm using python 2.7 I'm trying to figure out a way to change the names of my lists automatically.
Let me explain i have multiple lists
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 9, 3]
list3 = [8, 4, 3, 2, 1]
I would like to call the lists in a loop to determine which lists contain or do not contain a particular number.
My first thought was
x = "list" + str(i) # (where i iterates in the loop)
print x
However, using the above code only gave me the string "list1"(when i=1).
What I want is to be able to call the list that is named list1 and use the .count() operator to determine whether or not the number exists if it doesn't i want to call the next list until I'm out of lists(there will eventually be up to 30 lists).
Thanks,
Ryan
You shouldn't approach it like this. Put your lists in a container to iterate over them instead:
In [5]: for l in (list1, list2, list3):
...: print l.count(2)
...:
1
0
1
What you could do in a real-life use case is create a list of lists and fill it dynamically.
Then to get the first list that contains a given number, you could do:
In [6]: lists = [list1, list2, list3]
In [7]: next(l for l in lists if 9 in l)
Out[7]: [4, 5, 9, 3]
put the list in dict:
list1 = [1,2.4]
list2 = [2,5,6]
dlist = {1:list1,2:list2}
for k in dlist:
print dlist[k]

iterating through a list removing items, some items are not removed

I'm trying to transfer the contents of one list to another, but it's not working and I don't know why not. My code looks like this:
list1 = [1, 2, 3, 4, 5, 6]
list2 = []
for item in list1:
list2.append(item)
list1.remove(item)
But if I run it my output looks like this:
>>> list1
[2, 4, 6]
>>> list2
[1, 3, 5]
My question is threefold, I guess: Why is this happening, how do I make it work, and am I overlooking an incredibly simple solution like a 'move' statement or something?
The reason is that you're (appending and) removing from the first list whereby it gets smaller. So the iterator stops before the whole list could be walked through.
To achieve what you want, do this:
list1 = [1, 2, 3, 4, 5, 6]
list2 = []
# You couldn't just make 'list1_copy = list1',
# because this would just copy (share) the reference.
# (i.e. when you change list1_copy, list1 will also change)
# this will make a (new) copy of list1
# so you can happily iterate over it ( without anything getting lost :)
list1_copy = list1[:]
for item in list1_copy:
list2.append(item)
list1.remove(item)
The list1[start:end:step] is the slicing syntax: when you leave start empty it defaults to 0, when you leave end empty it is the highest possible value. So list1[:] means everything in it. (thanks to Wallacoloo)
Like some dudes said, you could also use the extend-method of the list-object to just copy the one list to another, if this was your intention. (But I choosed the way above, because this is near to your approach.)
As you are new to python, I have something for you: Dive Into Python 3 - it's free and easy. - Have fun!
You're deleting items from list1 while you're iterating over it.
That's asking for trouble.
Try this:
>>> list1 = [1,2,3,4,5,6]
>>> list2 = []
>>> list2 = list1[:] # we copy every element from list1 using a slice
>>> del list1[:] # we delete every element from list1
Essential debugging skill: Add print statements. (or print functions in Python 3)
>>> list1= [1, 2, 3, 4, 5, 6]
>>> for item in list1:
... print item
... list1.remove(item)
... print list1
...
1
[2, 3, 4, 5, 6]
3
[2, 4, 5, 6]
5
[2, 4, 6]
Notice that Python is trying to step through the positions of the list, but you keep removing items from the list, making the positions become meaningless.
Python picks the item at position 0 from the list.
You then remove the item, changing the list.
Python then picks the item at position 1 from the list (appearing to skip an item)
You then remove that item, changing the list.
Python then picks the item at position 2 from the list (appearing to skip an item)
You then remove the item, changing the list.
Python would then like to pick the item at position 3, but there's no such item. So the loop stops.
You shouldn't modify a list while you iterate over it. This causes the iterator to point at the wrong item. After the first item is handled, the iterator is pointing at index = 1, but because you've removed an item, the next item is now at index zero, so it will be skipped. This is why you are only handling every other item.
Try:
list2.extend(list1) # This appends all items from list1 to list2.
del list1[:] # From ChristopheD's post.
Exactly as ChristopheD says.
Could do this:
list1 = [1, 2, 3, 4, 5, 6]
list2 = []
for item in list1:
list2.append(item)
list1 = []
That'll clear list1.
Edit He/she has updated their post. I'll leave this up as a slight alternative.
Try this instead:
list1 = [1, 2, 3, 4, 5, 6]
list2 = []
list2.extend(list1)
list1[:] = []
There is also the humble copy function (or deepcopy if you have complex objects and not just integers in your list):
from copy import copy
list2 = copy(list1)
You might get a more appropriate answer if you explain what you're trying to accomplish (unless you're just learning about python lists).
"Variables" in Python are just names/references, so the destructive copy you seem to want to do seems kind of strange. If you want list2 to have the same values as list1 you can just do:
list2 = list1 # now they are both referring to the same list
And if after that you want to use list1 for something else, you can just do:
list1 = ['A', 'B', 'C']
Using a list comprehension:
list2 = [item for item in list1]
Bind the name list2 to the the same object as list1:
list2 = list1
(Note that if you modify the contents of list1, list2 will be change accordingly.)
Create a copy of list1 and bind it to the name list2:
list2 = list1[:]
In this case list1 and list2 are different objects.
As you can see in other answers, you are trying to modify the list while iterating over it. This doesn't work. There are many ways to copy one list to another. I did some tests to see how fast each approach is:
>>> timeit.Timer('list2 = list1[:]', 'list1 = range(10**3)').timeit(10**6)
3.9134418964385986
>>> timeit.Timer('list2 = []; list2.extend(list1)', 'list1 = range(10**3)').timeit(10**6)
4.9082601070404053
>>> timeit.Timer('list2 = copy.copy(list1)', 'import copy; list1 = range(10**3)').timeit(10**6)
7.5023419857025146
>>> timeit.Timer('list2 = [i for i in list1]', 'list1 = range(10**3)').timeit(10**6)
95.697894811630249
The slice syntax is the fastest. It's much faster than using a list comprehension.
To clear a list, you can use:
del list1[:]
#potatocubed: Many of the answers given solve the trivial example you gave ("move list1 to list2"), but don't really explain the "why" of the deeper problem, which is modifying a list as you iterate over it. Study S.Lott's answer...

Categories