This question already has answers here:
Best way to check if an item is present in a list of lists? [duplicate]
(5 answers)
Closed 2 years ago.
Currently working on a small sudoku solver, i use the boolean
if 0 in BOARD_EASY:
do the thing
having board as this value for testing purposes:
BOARD_EASY =[
[7,2,5,8,1,3,6,4,9],
[4,8,6,9,2,7,1,5,3],
[3,1,9,6,5,4,8,7,2],
[5,6,4,2,7,1,3,9,8],
[8,9,1,5,3,9,4,2,7],
[2,7,3,4,8,9,5,6,1],
[6,3,8,7,9,5,2,1,4],
[9,4,2,1,6,8,7,3,5],
[0,0,7,3,4,2,9,8,6]
]
for some reasons the boolean return false, while there is still 0's in the board, am i missing something?
It doesn't seems to check like the the first row of board_easy (i tried by removing the last digit for exemple)
Edit : Allowed me to finish my project, thank y'all ! (https://github.com/Lem0nRavioli/sudoku_solver)
I believe the in operator doesn't check nested values, just first level.
So it's looking through your list and it's only seeing other lists. See below.
BOARD_EASY =[
[7,2,5,8,1,3,6,4,9], #-> list
[4,8,6,9,2,7,1,5,3], #-> list
[3,1,9,6,5,4,8,7,2], #-> list
[5,6,4,2,7,1,3,9,8], #-> list
[8,9,1,5,3,9,4,2,7], #-> list
[2,7,3,4,8,9,5,6,1], #-> list
[6,3,8,7,9,5,2,1,4], #-> list
[9,4,2,1,6,8,7,3,5], #-> list
[0,0,7,3,4,2,9,8,6] #-> list
]
So the correct solution would be to loop through the list of lists BOARD_EASY then loop through the contents of each list as such:
for nested_list in BOARD_EASY:
for items in nested_list:
if 0 in items:
print("Found!")
I know you already have a response for this, I wanted to share an option that minimize the iteration using any
if any(0 in elem for elem in BOARD_EASY):
print ('0 is found in BOARD_EASY')
else:
print ('0 is NOT found in BOARD_EASY')
The importance of any function is that it short-circuits the execution as soon as it finds the value. So it does not iterate through the full list.
Looking at your code, your if statement if 0 in BOARD_EASY: will result in if (0 == BOARD_EASY[0]) or (0 == BOARD_EASY[1]) ...... The list has many elements so the compare is not correct. You need to look for each item in the list and compare the elements in the inner list. With the code above (with any function), it does the trick.
Per the docs for the in operator:
The operators in and not in test for membership. x in s evaluates to True if x is a member of s, and False otherwise.
0 is not a member of BOARD_EASY. The list [0,0,7,3,4,2,9,8,6] is.
So you could do something like:
any(0 in elem for elem in BOARD_EASY)
You could use numpy.flatten:
BOARD_EASY = np.array(BOARD_EASY).flatten()
print("do the thing") if 0 in BOARD_EASY else False
do the thing
I see all answers are iterating through all elements, or copying all of the data, or implementing 3 lines of code to do it, so here is a fast and simple solution:
if 0 in itertools.chain(*BOARD_EASY):
do the thing
What chain does is it iterates through each item in BOARD_EASY, as if it was iterating through just one list.
BOARD_EASY is a list of lists. BOARD_EASY does not contain a 0...it contains 9 lists.
Here, look:
BOARD_EASY = [
[7, 2, 5, 8, 1, 3, 6, 4, 9],
[4, 8, 6, 9, 2, 7, 1, 5, 3],
[3, 1, 9, 6, 5, 4, 8, 7, 2],
[5, 6, 4, 2, 7, 1, 3, 9, 8],
[8, 9, 1, 5, 3, 9, 4, 2, 7],
[2, 7, 3, 4, 8, 9, 5, 6, 1],
[6, 3, 8, 7, 9, 5, 2, 1, 4],
[9, 4, 2, 1, 6, 8, 7, 3, 5],
[0, 0, 7, 3, 4, 2, 9, 8, 6]
]
for i, x in enumerate(BOARD_EASY):
print(i+1, x)
Result:
1 [7, 2, 5, 8, 1, 3, 6, 4, 9]
2 [4, 8, 6, 9, 2, 7, 1, 5, 3]
3 [3, 1, 9, 6, 5, 4, 8, 7, 2]
4 [5, 6, 4, 2, 7, 1, 3, 9, 8]
5 [8, 9, 1, 5, 3, 9, 4, 2, 7]
6 [2, 7, 3, 4, 8, 9, 5, 6, 1]
7 [6, 3, 8, 7, 9, 5, 2, 1, 4]
8 [9, 4, 2, 1, 6, 8, 7, 3, 5]
9 [0, 0, 7, 3, 4, 2, 9, 8, 6]
The equivalent code you're looking for checks each list in sequence:
for i, l in enumerate(BOARD_EASY):
if 0 in l:
print("There's a zero in row " + str(i + 1))
Result:
There's a zero in row 9
Board_easy is a list of lists so the first element is [7,2,5...] not 7. You will need a nested for loop to iterate over each dimension
Nested for loops are unnecessary if you are only checking for membership of the element in one of your indices:
for count, i in enumerate(BOARD_EASY):
if 0 in i:
print("Found it in index", count)
Thanks for all the answers, allowed me to understand what was going on with the 'in' operator.
Ended up using a line related to the one of David Erickson:
# start of the script
BOARD_EASY = np.array(BOARD_EASY)
#
#
if 0 in np.concatenate(BOARD_EASY):
do the thing
I'd like a minor clarification of the topic at:
How to slice a list from an element n to the end in python?
I want to slice a list inside a loop, so that the last iteration of the loop includes the last element of the list. The only way I've found to do this so far (based on the answers in the other thread) is as follows:
>>> x = list(range(1,11))
>>> for i in range(0,4):
... x[i:-3+i if -3+i != 0 else None]
The values of x that I expect in each iteration are:
[1, 2, 3, 4, 5, 6, 7]
[2, 3, 4, 5, 6, 7, 8]
[3, 4, 5, 6, 7, 8, 9]
[4, 5, 6, 7, 8, 9, 10]
It works, but is my solution really the most Python-esque way to accomplish this?
You're going to a lot of trouble for a straightforward task.
How about
x[i:i+7]
This gives the same output, and is much easier to read. The difficulty in your original approach seems to be working around the problem of the list end being 1 past element -1, but you can't designate this as element 0. You can fix the problem by using positive indexing alone.
I'm not exactly sure about what your question is, but I think that using a simpler approach would work as well:
x = list(range(1, 11))
slice_length = 7
number_of_iterations = 4
# All you had to do was to first iterate
for i in range(number_of_iterations):
# Then slice the list from i to i+7 in your case
print(x[i:i+slice_length])
# Output:
# [1, 2, 3, 4, 5, 6, 7]
# [2, 3, 4, 5, 6, 7, 8]
# [3, 4, 5, 6, 7, 8, 9]
# [4, 5, 6, 7, 8, 9, 10]
Let's say I have an array defined as
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
and I wanted to get a vertical slice, returning [2, 5, 8]. Is there any way to do this with slicing syntax in straight Python? When I try to look up multidimensional slicing, the only results I tend to see are all talking about numpy, and using the syntax discussed there gives errors in raw Python.
I don't know of a direct way to get a vertical slice and this is probably more expensive than the list comprehension answer but still
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
list(zip(*z)[1])
[2, 5, 8]
Or this may be slightly less expensive
from itertools import izip, islice
list(*islice(izip(*z), 1, 2))
[2, 5, 8]
Sure. You could generally use a for loop. Or simply you could code like:
>>> test = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
>>> [row[1] for row in test]
[2, 5, 8]
This piece of code will generate a new list for a vertical slice. If you really need a slice operation, the following code would be useful:
>>> [item for sublist in test for item in sublist][1::len(test[0])]
[2, 5, 8]
I'm teaching myself Python ahead of starting a new job. Its a Django job, so I have to stick to 2.7. As such, I'm reading Beginning Python by Hetland and don't understand his example of using slices to replicate list.extend() functionality.
First, he shows the extend method by
a = [1, 2, 3]
b = [4, 5, 6]
a.extend(b)
produces [1, 2, 3, 4, 5, 6]
Next, he demonstrates extend by slicing via
a = [1, 2, 3]
b = [4, 5, 6]
a[len(a):] = b
which produces the exact same output as the first example.
How does this work? A has a length of 3, and the terminating slice index point is empty, signifying that it runs to the end of the list. How do the b values get added to a?
Python's slice-assignment syntax means "make this slice equal to this value, expanding or shrinking the list if necessary". To fully understand it you may want to try out some other slice values:
a = [1, 2, 3]
b = [4, 5, 6]
First, lets replace part of A with B:
a[1:2] = b
print(a) # prints [1, 4, 5, 6, 3]
Instead of replacing some values, you can add them by assigning to a zero-length slice:
a[1:1] = b
print(a) # prints [1, 4, 5, 6, 2, 3]
Any slice that is "out of bounds" instead simply addresses an empty area at one end of the list or the other (too large positive numbers will address the point just off the end while too large negative numbers will address the point just before the start):
a[200:300] = b
print(a) # prints [1, 2, 3, 4, 5, 6]
Your example code simply uses the most "accurate" out of bounds slice at the end of the list. I don't think that is code you'd use deliberately for extending, but it might be useful as an edge case that you don't need to handle with special logic.
It's simply an extension of normal indexing.
>>> L
[1, 2, 3, 4, 5]
>>> L[2] = 42
>>> L
[1, 2, 42, 4, 5]
The __setitem__() method detects that a slice is being used instead of a normal index and behaves appropriately.
a = [1, 2, 3]
b = [4, 5, 6]
a[len(a):] = b
means element in a from position len(a) are elements in b. Which means extending a with b.
For a demonstration, consider looking at a subclass of list:
from __future__ import print_function # so I can run on Py 3 and Py 2
class EdList(list):
def __setitem__(self,index,value):
print('setitem: index={}, value={}'.format(index,value))
list.__setitem__(self,index,value)
print(self)
def __setslice__(self,i,j,seq):
print('setslice: i:{}, j:{}, seq:{}'.format(i,j,seq))
self.__setitem__(slice(i,j),seq)
Running on Python 3:
>>> a=EdList(range(10))
>>> a[300000:]=[1,2,3]
setitem: index=slice(300000, None, None), value=[1, 2, 3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
>>> a[1:1]=[4,5,6]
setitem: index=slice(1, 1, None), value=[4, 5, 6]
[0, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
Running on Python 2:
>>> a=EdList(range(10))
>>> a[300000:]=[1,2,3]
setslice: i:300000, j:9223372036854775807, seq:[1, 2, 3]
setitem: index=slice(300000, 9223372036854775807, None), value=[1, 2, 3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
>>> a[1:1]=[4,5,6]
setslice: i:1, j:1, seq:[4, 5, 6]
setitem: index=slice(1, 1, None), value=[4, 5, 6]
[0, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
It is confusing when you are first learning it, but you will learn to love it I think.