Increment array in python, like a base number system - python

Say I have an array like [0 0 0 0] and I want to iterate it on a base-like scale. So say I pick base 100, and assume that I want to do it in a little endian system. My output would look like:
[1 0 0 0]
[2 0 0 0]
...
[99 0 0 0]
[0 1 0 0]
My code currently is in a function 'indexArray' but I was wondering it it was possible to do this without an if statement in a much simpler way?
def indexArray(enteredArr):
enteredArr[0] += 1
for i in range(len(enteredArr)):
if enteredArr[i] > 99:
enteredArr[i] = 0
enteredArr[i + 1] += 1
return enteredArr

As usual in Python, there's an easier way if you look for it.
Your main loop could be:
for i in itertools.product(range(BASE), repeat=NDIM):
... stuff ...
For your example, BASE=100 and NDIM=4, but the same approach works for any other values.
i will be a tuple of array values counting up like (0, 0, 0, 0), (0, 0, 0, 1) ... (BASE-1, BASE-1, BASE-1, BASE-1).

num = 45
base = 3
num_base = []
remainder = num
# the remainders of the integer divisions of the number by the base are the digits of the number in the new base
# see also here: https://math.stackexchange.com/questions/111150/changing-a-number-between-arbitrary-bases
while remainder:
num_base.append(remainder % base)
remainder //= base
# join the list in reverse while changing type of digits to characters
print("".join(str(x) for x in num_base[::-1]))

Related

New values for intervals of numbers

I have numpy arrays that look like this:
[2.20535093 2.44367784]
[7.20467093 1.54379728]
.
.
.
etc
I want to take each array and convert it like this:
[1 1]
[2 0]
0 means that the values are below 2. 1 means that the values are between 1 and 3. 2 means they are above 3.
I want to use a switch case function in python for this.
This is what I wrote until now:
def intervals(input):
match input:
case num if 0 <= num.all() < 2:
input = 0
case num if 2 <= num.all() < 3:
input = 1
case num if 3 <= num.all() <= math.inf:
input = 2
return input
But it doesn't seem to work as expected.
Without using a switch case, you can use:
num = np.array([[2.20535093, 2.44367784],
[7.20467093, 1.54379728]])
print(num) # [[2.20535093 2.44367784], [7.20467093 1.54379728]]
num[num < 2] = 0
num[np.logical_and(num > 1, num < 3)] = 1
num[num > 3] = 2
print(num) # [[1 1], [2 0]]
Your first two conditions are in conflict, since a value could be at the same time below 2 and between 1 and 3. Assuming the "below 2" condition wins in this case, a one line solution to your problem could be like that:
import numpy as np
arr = np.random.rand(5000000, 2)
new_arr = (arr > 2) + (arr > 3)
Here you are assigning +1 if value is above 2 and +1 if value is above 3 (Trues are casted to int and summed).
The approach is also slightly faster that other proposed solution, though less readable.

Function in python that outputs either -1 or 0 or 1

Is there like a (modified) round function where the output would be either -1,0,1 depending on to what number is the input the closest? E.g. 0 => 0, -2154 => -1, 10 => 1
Currently I am using normal if else statements:
if i == 0:
return 0
elif i > 0:
return 1
else:
return -1
But is there any way how I can make this a one-line code? By for instance using some modified round function.
You can use numpy.sign()
import numpy as np
print(np.sign(1.2))
print(np.sign(-3.4))
print(np.sign(0))
output:
1.0
-1.0
0
Without any imports:
def sign(i):
return (i>0) - (i<0)
print(sign(1))
print(sign(-3))
print(sign(0))
output:
1
-1
0
Here is a one-liner function using plain vanilla python and no imports. It can hardly get simpler than this.
def f(i):
return -1 if i < 0 else int(bool(i))
In [5]: f(0)
Out[5]: 0
In [6]: f(1)
Out[6]: 1
In [7]: f(-5)
Out[7]: -1
As the other answer commented, you can do it easily by using the numpy.sign() method, that directly returns your desired result.
However, you can do it directly using the built-in math function and the method copysign(x, y), which copies the sign of the second value to the first. By setting the first value as a boolean it will be interpreted as 0 if the original value is 0, and 1 otherwise. Then we copy the sign of value, which will transform the 1 into -1 or leave it positive.
from math import copysign
values = [1, 200, 0, -3, 45, -15]
for value in values:
print(int(copysign(bool(value), value)))
which outputs:
1
1
0
-1
1
-1

List of binary numbers: How many positions have a one and zero

I have a list of integers, e.g. i=[1,7,3,1,5] which I first transform to a list of the respective binary representations of length L, e.g. b=["001","111","011","001","101"] with L=3.
Now I want to compute at how many of the L positions in the binary representation there is a 1 as well as a zero 0. In my example the result would be return=2 since there is always a 1 in the third (last) position for these entries. I would be happy for any comment. I think, ideally I should do many Xor operations at the same time. However, I'm not sure how I can do this efficiently.
Edit: Thanks for the many answers!! I have to check which one is the fastest.
One observation is that if you take the AND of all numbers, and also the OR of all numbers, then the XOR of those two results will have a 1 where the condition is fulfilled.
So:
from functools import reduce
from operator import and_, or_
def count_mixed_bits(lst):
xor = reduce(and_, lst) ^ reduce(or_, lst)
return bin(xor).count("1")
count_mixed_bits([1,7,3,1,5]) # 2
There's a numpy.binary_repr method that accepts length. Unfortunately, it can't handle arrays. But you can apply a functionality of np.unravel_index instead:
def check(arr, lenght):
positions = np.array(np.unravel_index(i, (2,)*lenght))
return positions, np.sum(np.sum(positions, axis=1) != len(arr))
>>> positions, output = check(i, 3)
>>> print(positions)
>>> print(output)
[[0 1 0 0 1]
[0 1 1 0 0]
[1 1 1 1 1]]
2
Here is a solution, I suspect it is not very efficient, but it is easy to understand.
I loop over the digits and find the unique set, then I count the number of entries with a set length of two:
# create a binary list of 3 elements from input list of integers
i=[1,7,3,1,5]
b=['{0:03b}'.format(x) for x in i]
# loop over the digit position (1,2,3)
cnt=[]
for pos in range(3):
cnt.append(len(set([c[pos] for c in b])))
# cnt now contains a list of either 2(=both 1 and 0 present) or 1 (unique)
# so now we count the number of entries with "2"
result=cnt.count(2)
print (result)
answer:
2
First of all your question is tagged with numpy but your array is not a numpy array.
Here is a solution that uses numpy:
import numpy as np
def has_zeroes_and_ones_at_index(arr, index_from_right):
shifted_arr = np.right_shift(arr, index_from_right)
has_one_at_index = shifted_arr % 2 == 1
return(True in has_one_at_index and False in has_one_at_index)
arr = np.array([1, 7, 3, 1, 5])
res= has_zeroes_and_ones_at_index(arr, 1)
print(res)
Because the numbers are stored in binary we can use bit shifting to move all bits of the numbers to the right and then look at the last bit. We dont have to cast them to a binary format before.
5 (101) right shift by one -> 2 (010)
We then create a mask to see which numbers have a one in the last bit and return True when in the mask there is at least one True element and one false element.
You can use python bitwise operators for this task.
def find(aList, nn):
return sum(
filter(
lambda bb: bb > 0 ,
(
( 1 <= (sum( (aa & 1<<kk) > 0 for aa in aList)) < len(aList) )
for kk in range(nn)
)
)
)
>>> find([1,7,3,1,5],3)
2
>>> find([],3)
0
>>> find([7],3)
0
>>> find([7,1],3)
2
>>> find([7,1,7],3)
2

How to combine the result of nested loop in Python

I need help to do the combination of nested loop output from two iteration.
This is my nested while code:
iteration=0
while (iteration < 2):
count = 0
bit=5
numbers = []
while (count < bit):
Zero = 0
One = 1
IV=(random.choice([Zero, One]))
numbers.append(IV)
count= count + 1
print ('List of bit:', numbers)
iteration=iteration + 1
print ("End of iteration",iteration)
And this is the result:
List of bit: [1, 0, 1, 1, 0]
End of iteration 1
List of bit: [1, 0, 0, 1, 1]
End of iteration 2
However, I would like to combine the result of the loop. Supposedly, the result may produce something like this:
Combination of bit:[1, 0, 1, 1, 0 ,1 , 0, 0, 1, 1]
Hopefully someone may help me to do this.
Thank you so much.
This code should definitely be reorganized, but here is the solution.
from itertools import chain
# list for appending results
combined = []
iteration=0
while (iteration < 2):
count = 0
bit=5
numbers = []
while (count < bit):
Zero = 0
One = 1
IV=(random.choice([Zero, One]))
numbers.append(IV)
count= count + 1
print ('List of bit:', numbers)
iteration=iteration + 1
print ("End of iteration",iteration)
# append the result
combined.append(numbers)
# print the combined list
print(list(chain.from_iterable(combined)))
Output
[1, 0, 1, 1, 0 ,1 , 0, 0, 1, 1]
Simply initialize numbers outside the loop, instead of clearing it for every iteration, so that your results can keep appending to numbers.
iteration=0
numbers = []
while (iteration < 2):
count = 0
bit=5
while (count < bit):
Zero = 0
One = 1
IV=(random.choice([Zero, One]))
numbers.append(IV)
count= count + 1
print ('List of bit:', numbers)
iteration=iteration + 1
print ("End of iteration",iteration)
Given that the code simply creates a list of 10 random binary values, the code seems extremely complex. You could get the same effect with the following:
>>> import random
>>> [random.choice([0,1]) for _ in range(10)]
[0, 0, 0, 0, 1, 0, 1, 0, 1, 1]
However, as the code stands the list of values produced each iteration is thrown away at the start of the next iteration by the line numbers = [].
Either move this before the initial while statement, or create a separate list outside the while statement and append each iteration to it.
This latter approach (with minimal changes to your code) would look like this:
iteration=0
all_numbers = [] # List to hold complete set of results
while (iteration < 2):
count = 0
bit=5
numbers = []
while (count < bit):
Zero = 0
One = 1
IV=(random.choice([Zero, One]))
numbers.append(IV)
count= count + 1
print ('List of bit:', numbers)
iteration=iteration + 1
print ("End of iteration",iteration)
all_numbers.extend(numbers) # Add the iteration to the complete list
print ('Complete list', all_numbers) # Show the aggregate result
your numbers variable is being re-initialized in the outer loop.
Other answers already pointed where your error was, but really that's WAY too much code for such a simple thing. The pythonic way is a much simpler and more readable one-liner:
numbers = [random.randint(0,1) for i in range(10)]

Replacing one number with another in PYTHON

I have declared a board array which is 10*10.I am reading the elements of the board which are 0, 1, and 2. After reading my board looks somewhat like this (shorter version 4*4)
0 1 0 2
2 1 0 1
0 2 1 0
1 2 1 0
Code:
board = []
for i in xrange(0, 10)
board.append(raw_input())
now i want to change all occurences of 0 to 1. I am not able to change it..what should i do..please write the modified code..(getting error as immutable)
Thanks for the answer it got changed.I should first covert the list to string then use replace function
As I understood, you have a list and just want to replace all 0's with 1's right? If it's like that, you can try to convert that list to string and use the replace method. Like: board = str(board) and then board = board.replace('0','1'). And then convert back to list with eval built-in function. But this may be too slow for big lists .
UPDATE >> If you do not want to use strings you can also code this:
If it is a 2d list like: L = [[1, 1, 0], [0, 2, 1], [0, 0, 0]] then:
for x in L:
for y in x:
if y == 0:
x[x.index(y)] = 1
And if it is just a common list like L = [1, 0, 2, 1, 0, 1] then:
for x in L:
if x == 0:
L[L.index(x)] = 1
for i in xrange(10):
for j in xrange(10):
if board[i][j] == 0:
board[i][j] = 1
This should works. If not, please show me how you create your board table.

Categories