Nested List declaration [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
mytest=[[False]*3]*2
In [46]: mytest
Out[46]: [[False, False, False], [False, False, False]]
In [47]: mytest[0][1]=True
In [48]: mytest
Out[48]: [[False, True, False], [False, True, False]]
On the other hand
mytest=[ [False]*3 for i in range(2)]
In [53]: mytest[0][1]=True
In [54]: mytest
Out[54]: [[False, True, False], [False, False, False]]
On the first when in set [0][1], it sets at two places , but in second it sets correctly .. what is wrong with first assignment.

This is how Python handles objects. In your first example, the list mytest contains two [False, False, False] lists that are stored at the same memory location (i.e., both items in the list are pointing to the same memory location). When you change the one, the other is changed as well because simply they are both pointing to the same list in memory.
In the second example, and when you are using list comprehension the two lists [False, False, False] are two different objects pointing to different memory locations.
Proof
>>> mytest=[[False]*3]*2
>>> id(mytest[0])
4340367304
>>> id(mytest[1])
4340367304
>>> mytest=[ [False]*3 for i in range(2)]
>>> id(mytest[0])
4340436936
>>> id(mytest[1])
4340498512
The difference with the first and second statement is that your first statement will first evaluate [False] * 3 first which gives [False, False, False] and then *2 will create two references of that object ([False, False, False]). In the second example, you are creating a [False, False, False] each time.

Related

Why do '*' vs list comprehension when making list of lists work differently? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 2 years ago.
My purpose was to make 2D list by *
list2 = [[False]*2]*3 #[[False,False],[False,False],[False,False]]
list3 = [[False]*2 for _ in range(3)] #same as list2
list2[0][0] = True # [[True, False], [True, False], [True, False]]
list3[0][0] = True # [[True, False], [False, False], [False, False]]
list3 works well but list2 doesn't. list2 is affected by 'x' of list2[z][x].
What happened?
* operator concats the list and makes same replica or reference of the list so change made at one place will get replicated at all places whereas for _ range(3) will evaluate one by one hence making just one change at position list[0][0]

Combining boolean masks, why is in Python: [False, True] and [True, False] == [True, False] [duplicate]

This question already has answers here:
What is Truthy and Falsy? How is it different from True and False?
(8 answers)
Closed 2 years ago.
I was busy with combining masks and it strikes me that:
>>> [False, True] and [True, False]
[True, False]
and
>>> [True, False] and [False, True]
[False, True]
Why is this the case? Why shouldn't I expect it to be [False, False] in both cases?
I also think this is why np.logical_and() exists in Numpy:
>> np.logical_and([True, False], [False, False])
array([False, False])
This is the same reason why:
>>> (1,2) and (3,4)
(3, 4)
You need to understand that this is not doing element-wise comparison as opposed to np.logical_and.
The way and works is, if you have a and b, it checks whether a is False, if yes, return a else return b, does not matter what the value of b is.
In your case [False, True] is not False:
>>> bool([False, True])
True
Because it is a non-empty list, even [False, False] is True.
So in the case of [False, True] and [True, False], it checks to see whether [False, True] is False, which it is not, so it returns the second value. Same for the other case.
A python implementation of the and or logic would be:
def AND(first, second):
if bool(first) == True:
return second
else:
return first
def OR(first, second):
if bool(first) == True:
return first
else:
return second

Python 2d array boolean reduction

I've got a 2D array comprised of boolean values (True,False). I'd like to consolidate the array to a 1D based on a logical function of the contents.
e.g.
Input:
[[True, True, False],
[False, False, False],
[True, True, True]]
Output (logical AND):
[False,
False,
True]
How would this be done without a loop ?
You can use Python's built-in all method with a list-comprehension:
[all(x) for x in my_list]
If that's still too loopy for you, combine it with map:
map(all, my_list)
Note that map doesn't return a list in Python 3. If you want a list as your result, you can call list(map(all, my_list)) instead.
You can do this without NumPy too. Here is one solution using list comprehension. Explanation: It will loop over sub-lists and even if one of the items in each sub-list is False, it outputs False else True.
inp = [[True, True, False],[False, False, False],[True, True, True]]
out = [False if False in i else True for i in inp]
print (out)
# [False, False, True]
Alternative (less verbose) as suggested by Jean below:
out = [False not in i for i in inp]
I'm assuming you want to apply logical ANDs to the rows. You can apply numpy.all.
>>> import numpy as np
>>> a = np.array([[True, True, False], [False, False, False], [True, True, True]])
>>> a
array([[ True, True, False],
[False, False, False],
[ True, True, True]])
>>>
>>> np.all(a, axis=1)
array([False, False, True])
For a solution without numpy, you can use operator.and_ and functools.reduce.
>>> from operator import and_
>>> from functools import reduce
>>>
>>> lst = [[True, True, False], [False, False, False], [True, True, True]]
>>> [reduce(and_, sub) for sub in lst]
[False, False, True]
edit: actually, reduce is a bit redundant in this particular case.
>>> [all(sub) for sub in lst]
[False, False, True]
does the job just as well.
You can do this with numpy with the numpy.all function:
>>> import numpy as np
>>> arr = np.array([[True, True, False],
... [False, False, False],
... [True, True, True]]
... )
>>> np.all(arr, axis=1)
array([False, False, True])
Here thus the i-th element is True if all elements of the i-th row are True, and False otherwise. Note that the list should be rectangular (all sublists should contain the same number of booleans).
In "pure" Python, you can use the all function as well, like:
>>> data = [[True, True, False], [False, False, False], [True, True, True]]
>>> list(map(all, data))
[False, False, True]
This approach will work as well if the "matrix" is not rectangular. Note that for an empty sublist, this will return True, since all elements in an empty sublist are True.
You can also do this with map and reduce:
from functools import reduce
l = [[True, True, False],
[False, False, False],
[True, True, True]]
final = list(map(lambda x: reduce(lambda a, b: a and b, x), l))
print(final)
# [False, False, True]
The benefit here is that you can change the reduce function to something else (say, an OR or something more adventurous).

Python - changing element value of a list in list [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 7 years ago.
I have a list in list. All the values are False. I have to change value to True of a very specific one.
s=[[False,False,False,False]
[False,False,False,False]
[False,False,False,False]
[False,False,False,False]]
I want to change it into this:
s=[[False,False,False,False]
[False,False,False,False]
[False,True,False,False]
[False,False,False,False]]
P.s.:
I tried doing this:
s[2][1]=True
But i got this:
[[False,True,False,False]
[False,True,False,False]
[False,True,False,False]
[False,True,False,False]]
Add commas in order to build your matrix.
s=[[False,False,False,False],
[False,False,False,False],
[False,False,False,False],
[False,False,False,False]]
s[2][1]=True
for i in s:
print i
Outputs:
[False, False, False, False]
[False, False, False, False]
[False, True, False, False]
[False, False, False, False]

Using numpy any() in bool array of arrays

I have a list of lists which are composed by bools, let's say l = [[False, False], [True, False]], and I need to convert l to a numpy array of arrays of booleans. I converted every sublist into a bool array, and the whole list to numpy array too. My current real list has a size of 121 sublists, and the result of np.any() throws just five results, not the 121 expected. My code is this:
>>> result = np.array([ np.array(extracted[aindices[i]:aindices[i + 1]]) for i in range(len(aux_regions)) ])
>>> np.any(result)
[false, false, false, false, false]
extracted[aindices[i]:aindices[i + 1]] is the sublist which I convert to a bool array. The list generated in the whole line is converted to array too.
In the first example l the expected result is, for every subarray (asuming the list as converted) should be [False, True]
What's is the problem using np.any? or the data types for the converted list are not the right ones?
If you have a list of list of bools, you could skip numpy and use a simple comprehension:
In [1]: l = [[False, False], [True, False]]
In [2]: [any(subl) for subl in l]
Out[2]: [False, True]
If the sublists are all the same length, you can pass the list directly to np.array to get a numpy array of bools:
In [3]: import numpy as np
In [4]: result = np.array(l)
In [5]: result
Out[5]:
array([[False, False],
[ True, False]], dtype=bool)
Then you can use the any method on axis 1 to get the result for each row:
In [6]: result.any(axis=1) # or `np.any(result, axis=1)`
Out[6]: array([False, True], dtype=bool)
If the sublists are not all the same length, then a numpy array might not be the best data structure for this problem.
This part of my answer should be considered a "side bar" to what I wrote above. If the sublists have variable lengths, the list comprehension given above is my recommendation. The following is an alternative that uses an advanced numpy feature. I only suggest it because it looks like you already have the data structures needed to used numpy's reduceat function. It works without having to explicitly form the list of lists.
From reading your code, I infer the following:
extracted is a list of bools. You are splitting this up into sublists.
aindices is a list of integers. Each consecutive pair of integers in aindices specifies a range in extracted that is a sublist.
len(aux_regions) is the number of sublists; I'll call this n. The length of aindices is n+1, and the last value in aindices is the length of extracted.
For example, if the data looks like this:
In [74]: extracted
Out[74]: [False, True, False, False, False, False, True, True, True, True, False, False]
In [75]: aindices
Out[75]: [0, 3, 7, 10, 12]
it means there are four sublists:
In [76]: extracted[0:3]
Out[76]: [False, True, False]
In [77]: extracted[3:7]
Out[77]: [False, False, False, True]
In [78]: extracted[7:10]
Out[78]: [True, True, True]
In [79]: extracted[10:12]
Out[79]: [False, False]
With these data structures, you are set up to use the reduceat feature of numpy. The ufunc in this case is logical_or. You can compute the result with this one line:
In [80]: np.logical_or.reduceat(extracted, aindices[:-1])
Out[80]: array([ True, True, True, False], dtype=bool)

Categories

Resources