replace matrix element python 3.4.3 - python

I need to replace an element of a matrix.
I initiate a 4x4 matrix through the command M=4*[4*[0]].
For example I want to change the (0,1) element.
For logic I write:
M[0,1]=1
and the error code says
TypeError: list indices must be integers, not tuple
So I try:
M[0][1]=1
but instead of change only the (0,1) element, it changes all the "second column" in this way:
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]
What's the problem? How can I replace only one element?

The problem is that when you do something like this:
M=4*[4*[0]]
You are not creating different lists, you are simply copying a reference to the same list four times. So if you make a change in one of your sublists with your methodology of creating that 4x4 matrix, you are seeing the expected behaviour.
Official documentation will explain this further as well
You should do something like this to achieve what you are looking for:
[[0 for x in range(4)] for x in range(4)]
Now, you have four different lists in your list. If you make a change it will only be with reference to that explicit index you provide.

create the Array like this:
M = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
then M[0][1] = 1 will work

Related

How to check that there is no `1` touching a border in a 2D-list of `0` and `1`

I need to consider a swimming pool "legitimate". For the given list, the function should return "illegitimate". However, my code returns "legitimate", even though I haven't done anything to the data.
This is the code that I tried and I was expecting/should return "illegitimate" before trying to modify the list.
pool = [[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[1, 1, 1, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0]]
def is_legitimate_pool(pool):
for r in range(len(pool)):
for l in range(len(pool[r])):
if pool[r][0] == 1 or pool[4][l] == 1:
return str("illegitimate")
elif pool[r][0] == 0 or pool[4][l] == 0:
return str("legitimate")
print(is_legitimate_pool(pool))
Solution
You could start off by checking if any element in the first and last sub-list is non-zero. Any non-zero integer i when passed to bool(i) will evaluate to True and only zero is "falsy" (see Truth Value Testing). This allows us to simply use the built-in any function for checking those two lists. If it returns True, at least one element is not zero.
Then we just iterate through the other sub-lists and check if their first or last element is falsy (i.e. zero). If at least one is not, we can immediately return. If we get to the end of the loop, that means the "pool is legitimate".
Code
LEGIT = "legitimate"
NOT_LEGIT = "illegitimate"
def is_legitimate_pool(pool: list[list[int]]) -> str:
if any(pool[0]) or any(pool[-1]):
return NOT_LEGIT
for row in pool[1:-1]:
if row[0] or row[-1]:
return NOT_LEGIT
return LEGIT
Test
test_pool1 = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[1, 1, 1, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
]
test_pool2 = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
]
test_pool3 = [
[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 0],
]
print(is_legitimate_pool(test_pool1)) # illegitimate
print(is_legitimate_pool(test_pool2)) # illegitimate
print(is_legitimate_pool(test_pool3)) # legitimate
Caveat
The assumption is of course, that we are only interested in the "borders of the pool" being 0 and that an element can only ever be 0 or 1. If you actually need to explicitly check for border elements being 1s, we'd have to be a little more strict:
def is_legitimate_pool(pool: list[list[int]]) -> str:
if any(element == 1 for element in pool[0] + pool[-1]):
return NOT_LEGIT
for row in pool[1:-1]:
if row[0] == 1 or row[-1] == 1:
return NOT_LEGIT
return LEGIT
Errors in your code
There are a number of problems with your original function. One of them is that you must not return, before you have checked each sub-list. You need to check each of them, but you have a statement returning "legitimate", if your elif-condition holds, which would interrupt the loop as soon as just one row satisfies that condition.
The second problem is that you have your indices all messed up. The expression if pool[r][0] == 1 or pool[4][l] == 1 is the equivalent of saying "if the zero-th element in row r or the l-th element in row 4 equals 1". So you the second part is only ever checking row 4. You should check row r in both cases, but for the 0-th and 4-th element in that row being 1, so something like this: if pool[r][0] == 1 or pool[r][4] == 1.
Finally, you are not accounting for the fact that the very first row and the very last row must not contain any 1 at all. You'd have to check that at some point (preferably before starting to loop).
Optimizations
Fixing those problems would make the function work correctly, but it would still be sub-optimal because you would only be able to work on 5x5-lists of lists since you hard-coded the index 4 in a row to mean the "last" element. If you instead use index -1 it will refer to the last element no matter how long the list is.
For the sake of readability, you should avoid "index-juggling" as much as possible and instead leverage the fact that lists are iterable and can therefore be used in for-loops that yield each element one after the other. That way we can explicitly name and work on each sub-list/row in pool, making the code much clearer to the reader/yourself.
str("legitimate") is a no-op on the string literal "legitimate". You don't need the str function.
You should avoid shadowing global names in a local namespace. That means, if you have a global variable named pool, you should not also have a locally scoped variable pool in your function. Change one or the other so they have distinct names.

Numpy: How to find the most frequent nonzero values in array?

Suppose I have a numpy array of shape (1,4,5),
arr = np.array([[[ 0, 0, 0, 3, 0],
[ 0, 0, 2, 3, 2],
[ 0, 0, 0, 0, 0],
[ 2, 1, 0, 0, 0]]])
And I would like to find the most frequent non-zero value in the array across a specific axis, and only returns zero if there are no other non-zero values.
Let's say I'm looking at axis=2, I would like to get something like [[3,2,0,2]] from this array (For the last row either 1 or 2 would be fine). Is there a good way to implement this?
I've tried the solution in this following question (Link) , but I am unsure how to modify it so that it excludes a specific value.Thanks again!
We can use numpy.apply_along_axis and a simple function to solve this. Here, we make use of numpy.bincount to count the occurrences of numeric values and then numpy.argmax to get the highest occurrence. If there are no other values than exclude, we return it.
Code:
def get_freq(array, exclude):
count = np.bincount(array[array != exclude])
if count.size == 0:
return exclude
else:
return np.argmax(count)
np.apply_along_axis(lambda x: get_freq(x, 0), axis=2, arr=arr)
Output:
array([[3, 2, 0, 1]])
Please note, that it will also return exclude if you pass an empty array.
EDIT:
As Ehsan noted, above solution will not work for negative values in the given array. For this case, use Counter from collections:
arr = np.array([[[ 0, -3, 0, 3, 0],
[ 0, 0, 2, 3, 2],
[ 0, 0, 0, 0, 0],
[ 2, -5, 0, -5, 0]]])
from collections import Counter
def get_freq(array, exclude):
count = Counter(array[array != exclude]).most_common(1)
if not count:
return exclude
else:
return count[0][0]
Output:
array([[-3, 2, 0, -5]])
most_common(1) returns the most occurring value in the Counter object as one element list with a tuple in which first element is the value, and second is its number of occurrences. This is returned as a list, thus the double indexing. If list is empty, then most_common has not found any occurrences (either only exclude or empty).
This is an alternate solution (maybe not as efficient as the above one, but a unique one) -
#Gets the positions for the highest frequency numbers in axis=2
count_max_pos = np.argmax(np.sum(np.eye(5)[arr][:,:,:,1:], axis=2), axis=2)[0]+1
#gets the max values in based on the indices
k = enumerate(count_max_pos)
result = [arr[0][i] for i in k]
print(result)
[3,2,0,1]

How can I keep a vector in the same order after removing an element in Python

I know this seems like such a simple question, but when I go to remove the last element of my vector it reorders my vector and won't keep 0 as the last element.
vec = [1, 1, 0, 1]
vec.remove(vec[3])
The remaining vec is [1, 0, 1] when I wanted it to stay in order as [1, 1, 0]
Thanks!
vec = [1, 1, 0, 1]
vec.remove(vec[3])
vec[3] is 1, so you are removing the first element whose value is 1, i.e., the first element. The remaining elements are [1, 0, 1]. No reordering has been done. This would have been obvious if you had used a wider variety of values in your list.
You want one of these:
vec.pop(3)
del vec[3]

List Malfunction? (Python)

I'm having problems with my lists.
Obviously, I have just missed something. :P
Can someone tell me what is going wrong here and how to fix it?
Here is where I am having the malfunction:
On = [0, 0, [[0, 0],[0,1]]]
tempList = []
tempList.append(On[2])
print(tempList)
tempList.append([On[0],On[1]+1])
print(tempList)
Just in case this is important, it is for my AI pathfinding.
The First Print:
[[[[0, 0]], [0, 1]]]
I wanted:
[[0,0],[0,1]]
The Second Print:
[[[[0, 0]], [0, 1]], [0, 2]]
I wanted:
[[0,0],[0,1],[0,2]]
On[2] is supposed to track my past movements.
I was trying to get my past movements (On[2]) to combine with the current movement.
I want the tempList to be like this:
[[0,1],[0,2],[0,3]]
But instead I get this:
[[[0,1],[0,2]],[0,3]]
On is stored in this format(Or supposed to be): [CurrentX,CurrentY,[[Step1X,Step1Y],[Step2X,Step2Y]] etc.
If you need any more info, just tell me what you need.
EDIT: The problem is whith the On and the tempList.
EDIT2: If you people need to, I can post all of the code so you can run it. :/
This line:
tempList.append([On[0],On[1]+1])
appends a list to the list. You want this:
tempList.extend([On[0], On[1] + 1])
On = [0, 1, [[0, 0],[0,1]]]
tempList = []
tempList.extend(On[2])
print(tempList)
tempList.append([On[0],On[1]+1]) # changing only this line
print(tempList)
...yields...
[[0, 0], [0, 1]]
[[0, 0], [0, 1], [0, 2]]
...which is the stated desired result.
If your Bottom comes out as...
[0, 0, [[[0,1],[0,2],[0,3]]]]
...when you want it to be...
[0, 0, [[0,1],[0,2],[0,3]]]
...then the problem may not be with tempList and its construction at all, but with the append call, which appends its argument as a single element.
That is to say:
a=[1,2]
b=[3]
a.append(b)
...results in...
a == [1,2,[3]]
...rather than...
a == [1,2,3]
...which I'm presuming is what you actually want.
For that result, use either
a += b
or
a.extend(b)

list inside list python

I am not looking to get an list inside list instead I just want to add zeros but do not know how. see code
def myconv(x,h):
q=[]
print(h)
for i in range(len_h):
q.append(h[len_h-1-i])
print(q)
q.insert(0,([0]*len_h)) #I want this to add just plain zeros to the array... not an array insdie an
#like it is doing here
q.insert(len(q)+1,(0]*len_h))
print(q)
print(myconv([6,7,8,9],[1,2,3,4,5,6,7,8,9,0]))
You want to use +, e.g. [0, 0, 0] + [2, 1, 3] == [0, 0, 0, 2, 1, 3], to concatenate an array onto the first. Otherwise, you'll need to insert (or append) items one at a time.
To demonstrate how list multiplication works:
>>> [0]*2
[0, 0]
>>> [0]*5
[0, 0, 0, 0, 0]
I prefer the in-place extend operation. Just don't assign to it, because like most all Python in-place methods, it returns None.
>>> l2.extend([0]*5)
>>> l2
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0]
You have two ways of doing this:
q = [0]*len_h + q
or
q[0:0] = [0]*len_h
q.insert(0,([0]*len_h))
This creates a list within a list because [0]*len_h creates a new list. This array is then inserted into q. Instead, insert each element into q without creating a new list.
for i in range(len_h):
q.insert(0, 0)

Categories

Resources