Python - Binary Text Replacer - python

So I am working on something and I need to replace substrings with spaces, and get every different combination of that substring with the spaces, I want to do this using binary as a comparison.
So e.g.
0 0 0 = A B C
0 0 1 = A B _
0 1 0 = A _ C
0 1 1 = A _ _
1 0 0 = _ B C
1 0 1 = _ B _
1 1 1 = _ _ _ (put in code formatting to keep shape)
I am using python and have this so far, but it just output's an empty array.
Please could somebody help? :)
string ="abcde"
binary5=["0"]
final=[]
for count in range(0,32):
counter=0
count =bin(count)
count=str(count)
count = count.lstrip('-0b')
for i in range(len(count)):
if count[i] == "1":
counter=counter+1
if counter<6:
binary5.append(count)
print(binary5)
for i in range(0,32):
bintest = str(binary5[i])
bintest.split()
string2=string
for x in range(0,len(string)):
try:
if bintest[x] == "1":
string2.split()
string2.pop[x]
string2.insert(x-1," ")
string2.join()
print(string2)
final.append(string2)
except:
pass
print(final)

You have a methodology problem: you specifically throw away your diagnostic information. Therefore, when you have a problem, you have no idea what you did wrong: you ignored the error message.
The try-except block has no relation to your algorithm. Get rid of it, and start debugging your code. The first error is
string2.pop[x]
There is no pop method for type string. Next, you keep splitting strings that have no spaces or punctuation; I'm not sure what you think this is doing.

I have no idea what your code is doing. It's way too complicated. Here's a direct replacement.
import string
from itertools import product
def translate_tuple(tup):
''' Takes a tuple of any length containing 0s or 1s.
Returns a new tuple with the correct letters. '''
return tuple(l if tup[i] == 0 else '_' for i, l in enumerate(string.ascii_letters[:len(tup)]))
def get_pairs(length):
''' Get all pairs of binary and translated text. '''
for binary_tup in product((0, 1,), repeat=length):
yield ' '.join(map(str, binary_tup)), ' '.join(translate_tuple(binary_tup))
for b, t in get_pairs(3):
print(f'{b} = {t}')
Which prints:
0 0 0 = a b c
0 0 1 = a b _
0 1 0 = a _ c
0 1 1 = a _ _
1 0 0 = _ b c
1 0 1 = _ b _
1 1 0 = _ _ c
1 1 1 = _ _ _
You can use arbitrary sized binary numbers by providing a different length to get_pairs()
In [36]: for i in range(10):
...: b, t = next(g)
...: print(f'{b} = {t}')
...:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = a b c d e f g h i j k l m n o p q r s t
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 = a b c d e f g h i j k l m n o p q r s _
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 = a b c d e f g h i j k l m n o p q r _ t
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 = a b c d e f g h i j k l m n o p q r _ _
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 = a b c d e f g h i j k l m n o p q _ s t
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 = a b c d e f g h i j k l m n o p q _ s _
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 = a b c d e f g h i j k l m n o p q _ _ t
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 = a b c d e f g h i j k l m n o p q _ _ _
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 = a b c d e f g h i j k l m n o p _ r s t
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 = a b c d e f g h i j k l m n o p _ r s _
Explanation
The most important bit is translate_tuple(), but you can use itertools.product to get all the input tuples.
translate_tuple(tup) expects a binary tuple of any length, e.g:
(0, 0, 0)
(0, 1, 0)
(1, 1, 1, 1)
(0, 1, 0, 1, 0)
And returns a new tuple in the format you described:
(0, 0, 0) => ('a', 'b', 'c')
(0, 1, 0) => ('a', '_', 'c')
(1, 1, 1, 1) => ('_', '_', '_', '_')
(0, 1, 0, 1, 0) => ('a', '_', 'c', '_', 'e')
The next function get_pairs() just generates all the binary tuples of a given length, and then yields the string of the binary tuple and the string of the result joined by spaces.
Then you can print out the strings. It would probably be better to yield the raw tuples, and create the strings immediately before printing, but I wanted to keep it mostly in that function.

Related

Mimicing 'n' Nested For Loops Using Recursion

I would like to create some number of for-loops equal to the length of a list, and iterate through the values in that list. For example, if I had the list:
[1,2,3,4]
I would like the code to function like:
for i in range(1):
for j in range(2):
for k in range(3):
for l in range(4):
myfunc(inputs)
I understand I would need to do this recursively, but I'm not quite sure how. Ideally, I would even be able to iterate through these list values by a variable step; perhaps I want to count by two's for one loop, by .8's for another, etc. In that case, I would probably deliver the information in a format like this:
[[value,step],[value,step] ... [value,step],[value,step]]
So, how could I do this?
Not quite sure what you want at the very end, but here's a way to recursively set-up your loops:
test = [1,2,3,4]
def recursive_loop(test):
if len(test) == 1:
for i in range(test[0]):
print('hi') # Do whatever you want here
elif len(test) > 1:
for i in range(test[0]):
recursive_loop(test[1:])
recursive_loop(test)
You can certainly do it with recursion, but there's already a library function for that:
itertools.product
from itertools import product
def nested_loops(myfunc, l):
for t in product(*(range(n) for n in l)):
myfunc(*t)
## OR EQUIVALENTLY
# def nested_loops(myfunc, l):
# for t in product(*map(range, l)):
# myfunc(l)
nested_loops(print, [1, 2, 3, 4])
# 0 0 0 0
# 0 0 0 1
# 0 0 0 2
# 0 0 0 3
# 0 0 1 0
# 0 0 1 1
# ...
# 0 1 2 1
# 0 1 2 2
# 0 1 2 3
You can of course include steps too. Library function zip can be useful.
def nested_loops_with_steps_v1(myfunc, upperbounds, steps):
for t in product(*(range(0, n, s) for n,s in zip(upperbounds, steps))):
myfunc(*t)
nested_loops_with_steps_v1(print, [1,2,8,10], [1,1,4,5])
# 0 0 0 0
# 0 0 0 5
# 0 0 4 0
# 0 0 4 5
# 0 1 0 0
# 0 1 0 5
# 0 1 4 0
# 0 1 4 5
Or if your steps and upperbounds are already zipped together:
def nested_loops_with_steps_v2(myfunc, l):
for t in product(*(range(0, n, s) for n,s in l)):
myfunc(*t)
nested_loops_with_steps_v2(print, [(1,1),(2,1),(8,4),(10,5)])
# 0 0 0 0
# 0 0 0 5
# 0 0 4 0
# 0 0 4 5
# 0 1 0 0
# 0 1 0 5
# 0 1 4 0
# 0 1 4 5

while loop that is equivalent to for loop

I am trying to experiment how the while loop works.
docs = ['123867', '256789', '3aa', '4gg', '5yy', '6abc']
for i in range(0,len(docs)):
for j in range(i,len(docs[i])):
print(i, j)
My output for the above code is
0 0
0 1
0 2
0 3
0 4
0 5
1 1
1 2
1 3
1 4
1 5
2 2
I attempt to play with the while loop with
docs = ['123867', '256789', '3aa', '4gg', '5yy', '6abc']
i = 0
j = i
while i < len(docs):
while j < len(docs[i]):
print(i, j)
j += 1
i += 1
but the output is
0 0
0 1
0 2
0 3
0 4
0 5
How can I fix my while loop to match the for loop? Thanks!
docs = ['123867', '256789', '3aa', '4gg', '5yy', '6abc']
i = 0
while i < len(docs):
j = i # should be moved here
while j < len(docs[i]):
print(i, j)
j += 1
i += 1

how to change string matrix to a integer matrix

I have a voting dataset like that:
republican,n,y,n,y,y,y,n,n,n,y,?,y,y,y,n,y
republican,n,y,n,y,y,y,n,n,n,n,n,y,y,y,n,?
democrat,?,y,y,?,y,y,n,n,n,n,y,n,y,y,n,n
democrat,n,y,y,n,?,y,n,n,n,n,y,n,y,n,n,y
but they are both string so I want to change them to integer matrix and make statistic
hou_dat = pd.read_csv("house.data", header=None)
for i in range (0, hou_dat.shape[0]):
for j in range (0, hou_dat.shape[1]):
if hou_dat[i, j] == "republican":
hou_dat[i, j] = 2
if hou_dat[i, j] == "democrat":
hou_dat[i, j] = 3
if hou_dat[i, j] == "y":
hou_dat[i, j] = 1
if hou_dat[i, j] == "n":
hou_dat[i, j] = 0
if hou_dat[i, j] == "?":
hou_dat[i, j] = -1
hou_sta = hou_dat.apply(pd.value_counts)
print(hou_sta)
however, it shows error, how to solve it?:
Exception has occurred: KeyError
(0, 0)
IIUC, you need map and stack
map_dict = {'republican' : 2,
'democrat' : 3,
'y' : 1,
'n' : 0,
'?' : -1}
df1 = df.stack().map(map_dict).unstack()
print(df1)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
0 2 0 1 0 1 1 1 0 0 0 1 -1 1 1 1 0 1
1 2 0 1 0 1 1 1 0 0 0 0 0 1 1 1 0 -1
2 3 -1 1 1 -1 1 1 0 0 0 0 1 0 1 1 0 0
3 3 0 1 1 0 -1 1 0 0 0 0 1 0 1 0 0 1
If you're dealing with data from csv, it is better to use pandas' methods.
In this case, you have replace method to do exactly what you asked for.
hou_dat.replace(to_replace={'republican':2, 'democrat':3, 'y':1, 'n':0, '?':-1}, inplace=True)
You can read more about it in this documentation

Using itertools to generate an exponential binary space

I am interested in generating all binary combination of N variables without having to implement a manual loop of iterating N times over N and each time looping over N/2 and so on.
Do we have such functionality in python?
E.g:
I have N binary variables:
pool=['A','B','C',...,'I','J']
len(pool)=10
I would like to generate 2^10=1024 space out of these such as:
[A B C ... I J]
iter0 = 0 0 0 ... 0 0
iter1 = 0 0 0 ... 0 1
iter2 = 0 0 0 ... 1 1
...
iter1022 = 1 1 1 ... 1 0
iter1023 = 1 1 1 ... 1 1
You see that I don't have repetitions here, each variable is enabled once per each of these iter's sequences. How can I do that using Python's itertools?
itertools.product with the repeat parameter is the simplest answer:
for A, B, C, D, E, F, G, H, I, J in itertools.product((0, 1), repeat=10):
The values of each variable will cycle fastest on the right, and slowest on the left, so you'll get:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 1 0 0
etc. This may be recognizable to you: It's just the binary representation of an incrementing 10 bit number. Depending on your needs, you may actually want to just do:
for i in range(1 << 10):
then mask i with 1 << 9 to get the value of A, 1 << 8 for B, and so on down to 1 << 0 (that is, 1) for J. If the goal is just to print them, you can even get more clever, by binary stringifying and then using join to insert the separator:
for i in range(1 << 10):
print(' '.join('{:010b}'.format(i)))
# Or letting print insert the separator:
print(*'{:010b}'.format(i)) # If separator isn't space, pass sep='sepstring'

Unable to retrieve required indices from multiple NumPy arrays

I have 4 numpy arrays of same shape(i.e., 2d). I have to know the index of the last array (d) where the elements of d are smaller than 20, but those indices of d should be located in the region where elements of array(a) are 1; and the elements of array (b) and (c) are not 1.
I tried as follows:
mask = (a == 1)|(b != 1)|(c != 1)
answer = d[mask | d < 20]
Now, I have to set those regions of d into 1; and all other regions of d into 0.
d[answer] = 1
d[d!=1] = 0
print d
I could not solve this problem. How do you solve it?
import numpy as np
a = np.array([[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0]])
b = np.array([[0,0,0,1,1,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0],
[0,0,0,1,0,1,0,0,0,0,0],
[0,0,0,1,1,1,0,1,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,1,0,1,0,0,0,0]])
c = np.array([[0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0,0],
[0,0,0,0,0,1,0,0,0,0,0]])
d = np.array([[0,56,89,67,12,28,11,12,14,8,240],
[1,57,89,67,18,25,11,12,14,9,230],
[4,51,89,87,19,20,51,92,54,7,210],
[6,46,89,67,51,35,11,12,14,6,200],
[8,36,89,97,43,67,81,42,14,1,220],
[9,16,89,67,49,97,11,12,14,2,255]])
The conditions should be AND-ed together, instead of OR-ed. You can first get the Boolean array / mask representing desired region, and then modify d based on it:
mask = (a == 1) & (b != 1) & (c != 1) & (d < 20)
d[mask] = 1
d[~mask] = 0
print d
Output:
[[0 0 0 0 0 0 0 1 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0]
[0 0 0 0 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0]]

Categories