Counting elements inside an array/matrix - python

I am struggling with what is hopefully a simple problem. Haven't been able to find a clear cut answer online.
The program given, asks for a user input (n) and then produces an n-sized square matrix. The matrix will only be made of 0s and 1s. I am attempting to count the arrays (I have called this x) that contain a number, or those that do not only contain only 0s.
Example output:
n = 3
[0, 0, 0] [1, 0, 0] [0, 1, 0]
In this case, x should = 2.
n = 4
[0, 0, 0, 0] [1, 0, 0, 0] [0, 1, 0, 0] [0, 0, 0, 0]
In this case, x should also be 2.
def xArrayCount(MX):
x = 0
count = 0
for i in MX:
if i in MX[0 + count] == 0:
x += 0
count += 1
else:
x += 1
count += 1
return(x)
Trying to count the number of 0s/1s in each index of the matrix but I am going wrong somewhere, could someone explain how this should work?
(Use of extra python modules is disallowed)
Thank you

You need to count all the lists that contain at least once the number one. To do that you can't use any other module.
def count_none_zero_items(matrix):
count = 0
for row in matrix:
if 1 in row:
count += 1
return count
x = [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0]]
count_none_zero_items(x)
Also notice that i changed the function name to lower case as this is the convention in python. Read more about it here:
Python3 Conventions
Also it's worth mentioning that in python we call the variable list instead of array.

Those look like tuples, not arrays. I tried this myself and if I change the tuples into nested arrays (adding outer brackets and commas between the single arrays), this function works:
def xArrayCount(MX):
x = 0
count = 0
for i in matrix:
if MX[count][count] == 0:
count += 1
else:
x += 1
count += 1
return x

Related

How to replace ones with the values present in x?

In place of 1 , x values should be filled according to the index.
My code is :
x = [0.5697071 0.47144773 0.45310486]
z_prime= [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1]]
flatten_matrix = [val for val in z_prime ]
for val in flatten_matrix:
for j in val:
if(j!=0):
z= x
else:
z = 0
print(z)
This gives the output as:
0
0
0
0
0
[0.5697071 0.47144773 0.45310486]
0
[0.5697071 0.47144773 0.45310486]
0
0
[0.5697071 0.47144773 0.45310486]
[0.5697071 0.47144773 0.45310486]
Expected Output:
[ [0, 0, 0], [0, 0, 0.45310486 ], [0, 0.47144773 , 0], [0, 0.47144773, 0.45310486],
Try this:
flatten_matrix = [[x[idx] if elm[idx] == 1 else 0 for idx in range(len(elm))] for elm in z_prime]
As a sidenote: I'd recommend breaking this up into a standalone function, because if you ever come back to this list comprehension it'll be incomprehensible.
Consider something like this (which may be sligthly less performant, but much more readable)
def flatten_matrix(x, z_prime):
if len(x) != len(z_prime[0]):
raise ValueError("x and z_prime must have the same number of columns")
#Maybe even add a check here that all the elements of z_prime are 0 or 1
#Or add a check that all elements in z_prime have the same length?
output = [[0] * len(x) for i in range(len(z_prime))] #Creates the output list with correct format
for row_idx, elm in enumerate(z_prime): #Iterates through the rows of z_prime
for col_idx, num in enumerate(elm): #Iterates through the columns of z_prime
if num == 1:
output[row_idx][col_idx] = x[col_idx]
else:
output[row_idx][col_idx] = 0
return output

In a one dimensional numpy array of 1's and 0's, how can I convert the next n elements following a 1 to 0's?

For a one dimensional numpy array of 1's and 0's, how can I effectively "mask" the array such that after the occurrence of a 1, the next n elements of the array are converted to zero. After the n elements have passed, the pattern repeats such that the first next occurrence of a 1 is preserved followed again by n zeros.
It is important that the first eligible occurrences of 1 are preserved, so a simple mask such as:
[true, false, false, true ...] won't work.
furthermore, the data set is massive so efficiency is important.
I've written crude python code to give me the desired results, but it is way too slow for what I need.
Here is an example:
data = [0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1]
n = 3
newData = []
tail = 0
for x in data:
if x == 1 and tail <= 0:
newData.append(1)
tail = n
else:
newData.append(0)
tail -= 1
print(newData)
newData: [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1]
Is there possibly a vectorized numpy solution to this problem?
I'm processing tens of thousands of arrays, with more than a million elements in each array. So far using numpy functions has been the only way to manage this.
As far as I know, there is no option completely in numpy to do this. You could still use numpy to reduce the time for grabbing the indices, though.
data = [0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1]
n=3
def get_new_data(data,n):
new_data = np.zeros(len(data))
non_zero = np.argwhere(data).ravel()
idx = non_zero[0]
new_data[idx] =1
idx += n
for i in non_zero[1:]:
if i > idx:
new_data[i] = 1
idx+=n
return new_data
get_new_data(data, n)
A function like this should give you a better run time since you are not looping over the whole array.
If this is still not optimal to you, you can look at using numba, which works very well with numpy and is relatively easy to use.
You could do it like this:-
N = 3
data = [0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1]
newData = data.copy()
i = 0
M = [0 for _ in range(N)]
while i < len(newData) - N:
if newData[i] == 1:
newData[i + 1:i + 1 + N] = M
i += N
i += 1
print(newData)

How to reduce higher values to 1s and sort the ones from right to left

I want to make a python program that quickly reduces a number greater than 1 in an array/list and places it in an empty spot before it. Say we have:
li = [4,1,0,0,0,1,3,0]
we'd get:
rtr = [1,1,0,1,1,1,1,0]
Note how the 4 turns into a 1 because it's already to the left and then the 3 gets divided into 2 positions before the 1 that has already been taken. Can anyone help me with this problem?
You can iterate the list from end to start and keep track of the sum you collect from the values. When you have a non zero sum, take 1 from it to populate the result list, and otherwise put a 0 in the result list.
Here is how that could work:
def spread(lst):
carry = 0
res = []
for i in reversed(lst):
carry += i
res.append(int(carry > 0))
if carry:
carry -= 1
return list(reversed(res))
lst = [4, 1, 0, 0, 0, 1, 3, 0]
print(spread(lst)) # [1, 1, 0, 1, 1, 1, 1, 0]
Using numpy
def fun(l):
s = np.array(l[::-1])
for i in range(len(s)):
if s[i] != 1 and s[i] != 0:
x = s[i+1:]
x[(x == 0).nonzero()[0][:s[i]-1]] = 1
s[i] = 1
return s[::-1].tolist()
print (fun([4,1,0,0,0,1,3,0]))
print (fun([0, 10]))
Output:
[1, 1, 0, 1, 1, 1, 1, 0]
[1, 1]

In order to generate all combinations of 1's and 0's we use a simple binary table. How can I easily create this binary table in an array?

For example the binary table for 3 bit:
0 0 0
0 0 1
0 1 0
1 1 1
1 0 0
1 0 1
And I want to store this into an n*n*2 array so it would be:
0 0 0
0 0 1
0 1 0
1 1 1
1 0 0
1 0 1
For generating the combinations automatically, you can use itertools.product standard library, which generates all possible combinations of the different sequences which are supplied, i. e. the cartesian product across the input iterables. The repeat argument comes in handy as all of our sequences here are identical ranges.
from itertools import product
x = [i for i in product(range(2), repeat=3)]
Now if we want an array instead a list of tuples from that, we can just pass this to numpy.array.
import numpy as np
x = np.array(x)
# [[0 0 0]
# [0 0 1]
# [0 1 0]
# [0 1 1]
# [1 0 0]
# [1 0 1]
# [1 1 0]
# [1 1 1]]
If you want all elements in a single list, so you could index them with a single index, you could chain the iterable:
from itertools import chain, product
x = list(chain.from_iterable(product(range(2), repeat=3)))
result: [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1]
Most people would expect 2^n x n as in
np.c_[tuple(i.ravel() for i in np.mgrid[:2,:2,:2])]
# array([[0, 0, 0],
# [0, 0, 1],
# [0, 1, 0],
# [0, 1, 1],
# [1, 0, 0],
# [1, 0, 1],
# [1, 1, 0],
# [1, 1, 1]])
Explanation: np.mgrid as used here creates the coordinates of the corners of a unit cube which happen to be all combinations of 0 and 1. The individual coordinates are then ravelled and joined as columns by np.c_
Here's a recursive, native python (no libraries) version of it:
def allBinaryPossiblities(maxLength, s=""):
if len(s) == maxLength:
return s
else:
temp = allBinaryPossiblities(maxLength, s + "0") + "\n"
temp += allBinaryPossiblities(maxLength, s + "1")
return temp
print (allBinaryPossiblities(3))
It prints all possible:
000
001
010
011
100
101
110
111

find the number of separated pairs in array

Good Morning,
I have a numpy array like:
[0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0]
and I would like to find the number of separated pairs of 1.
Three (or more) consecutive 1s count also as pair, i.e.: in this example the returned number should be 3.
What is the best technique to achieve this?
Thanks a lot!
using itertools.groupby,
k hold the unique key 0/1 based list lst below, g hold the correspond group iterator for the unique key k
import itertools
target = 1
lst = [0,1,1,0,1,1,1,0,0,1,0,1,1,0]
pair_count = 0
for k,g in itertools.groupby(lst):
if k==target and len(list(g))>1: # match target and more than 1 count as pair
pair_count += 1
# pair_count = 3
You can easily implement it yourself, see my code below:
l = [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0]
# Create flag to skip all elements that have >2 1 in sequence
added = False
pairs_counter = 0
for i in range(1, len(l)):
rem = l[i - 1]
if l[i] == 1 and rem == 1 and not added:
added = True
pairs_counter +=1
if l[i] == 0:
added = False
print (pairs_counter)
Complexity of this method is O(n)
I would go for something like this:
a = [0 1 1 0 1 1 1 0 0 1 0 1 1 0]
sum([
a[i-2] == a[i-1] == 1 and a[i] == 0
for i in xrange(2,len(a))
]) + (len(a) > 2 and a[-1] == a[-2] == 1)
It just keeps adding Trues and Falses together. I guess some people will find it ugly, I think it is OK.
It should be noted though, that if the list is really large, this is not a good option, since it creates the list of bools in memory. It would be easy to avoid that.
Use itertools.groupby and sum
sum(1 for target, group_count in itertools.groupby(lst)
if target == 1 and len(list(group_count)) >= 2)

Categories