Python convert String to Variable in the loop - python

I would like to do something like this:
x = 0
y = 3
TEST0 = 10
TEST1 = 20
TEST2 = 30
while x < y:
result = exec('TEST{}'.format(x))
print(result)
x += 1
And have the output:
10
20
30
Somehow convert TEST{variable} to the actual variable, or what is the way to do it?
Currently, I have result as:
None
None
None

Welcome to Python! What you need is a list:
x = 0
y = 3
TEST = [10, 20, 30]
while x < y:
result = TEST[x]
print(result)
x += 1
A list is created by putting the values between []. You access a particular element in the list by writing the name of the variable, followed by the index enclosed in []. Read more about lists here in the official tutorial.
Instead of the while loop with explicit indexing, it's nicer to use a for loop instead:
TEST = [10, 20, 30]
for element in TEST:
result = element
print(result)

I would recommend using a dictionary in most cases, however if you don't want to use a dictionary you can always use globals() or vars(). They work as follows:
global_var = 5
>> 5
print(globals()["global_var"])
>> 5
vars() works in the same way but at module scope.
In your case, do the following:
x = 0
y = 3
TEST0 = 10
TEST1 = 20
TEST2 = 30
while x < y:
result = globals()['TEST{}'.format(x)]
print(result)
x += 1

Related

question regarding while loops and variable indexing

I am new to coding, so forgive me if this is answered elsewhere. I am not sure what to search for to find a relevant answer. I also am not sure if my title is even correct. I want to print out each value in C_numbers that is associated with the same index in barcode_names. I want to separate these numbers each time the value in barcode_names changes. So I am using a third list unique_barcodes to compare to.
barcode_names = [1111,1111,1111,2222,2222,2222,3333,3333]
C_numbers = [12,5,7,28,32,13,2,9]
unique_barcodes = [1111,2222,3333]
x = 0
y = 0
for z in barcode_names:
if barcode_names[x] == unique_barcodes[y]:
print(C_numbers[x])
x = x+1
else:
y = y+1
print('next page')
result:
12
5
7
next page
28
32
13
next page
For some reason, it doesn't print the last two values 2 and 9. How do I get it to continue looping until it finishes printing all the values?
You're looping over barcode_names, so the most iterations that loop can make is eight. Increasing y while printing next page counts as one of those iterations. This prevents you from doing the last two things you wanted to do, as then you'd need a total of ten iterations. To fix this, you need to keep looping as long as x is a valid index in barcode_names. Change for z in barcode_names: to while x < len(barcode_names):.
Using x and y was throwing off your loop and is why it didn't complete.
Maybe something like this is more simple?
barcode_names = [1111,1111,1111,2222,2222,2222,3333,3333]
C_numbers = [12,5,7,28,32,13,2,9]
last_name = barcode_names[0]
for i in range(len(barcode_names)):
barcode_name = barcode_names[i]
if not barcode_name == last_name:
last_name = barcode_name
print('next page')
print(C_numbers[i])
result:
12
5
7
next page
28
32
13
next page
2
9
The loop control variable z is not stopping itself from being incremented when y index value is incrementing. Hence, before your desired print, the loop gets terminated.
I found this by adding the following line to your code inside the loop at the beginning
print('z value: ', z)
i.e. complete program becomes:
barcode_names = [1111,1111,1111,2222,2222,2222,3333,3333]
C_numbers = [12,5,7,28,32,13,2,9]
unique_barcodes = [1111,2222,3333]
x = 0
y = 0
for z in barcode_names:
print('z value: ', z)
if barcode_names[x] == unique_barcodes[y]:
print(C_numbers[x])
x = x+1
else:
y = y+1
print('next page')
Output:
z value: 1111
12
z value: 1111
5
z value: 1111
7
z value: 2222
next page
z value: 2222
28
z value: 2222
32
z value: 3333
13
z value: 3333
next page
>
Try this instead:
barcode_names = [1111,1111,1111,2222,2222,2222,3333,3333]
C_numbers = [12,5,7,28,32,13,2,9]
unique_barcodes = [1111,2222,3333]
x = 0
y = 0
for z in barcode_names:
# print('z value: ', z)
if barcode_names[x] != unique_barcodes[y]:
y = y+1
print('next page')
print(C_numbers[x])
x = x+1
Output:
12
5
7
next page
28
32
13
next page
2
9
>

Applying a custom function to a column in a dataframe

I have a custom function that takes in a 8-character identifier (CUSIP), and based on some logic generates the 9th character (check bit). I want to apply this function to a dataframe consisting of 8-char identifiers and return back the dataframe with the full 9-char string.
e.g. a list of 2 8-char cusips:
list1 = [[ '912810SE',
'912810SF']]
pd1 = pd.DataFrame(list1)
print(pd1.apply(gen_cusip_checkbit))
I am expecting 9 and 6; however, I am getting 4 and 2 when applying the function to the df. Also, this should loop 8 times in the function, but when applied to the df it loops 36 times.
This is the function:
def gen_cusip_checkbit(cusip):
cusip=str(cusip).upper()
sumnum = 0
for i in range(len(cusip)):
val = 0
if cusip[i].isnumeric():
val = int(cusip[i])
else:
val = int(cusip_alpha.find(cusip[i])+10) # refers to alphabet string for mapping
if i % 2 != 0:
val *= 2
val = (val % 10) + (val // 10)
sumnum += val
return str((10 - (sumnum % 10)) % 10)
so it looks like when you do :
pd1.apply(gen_cusip_checkbit)
The variable sent to the function consists of :
0 912810SE
NAME: 0, DTYPE: OBJECT
The length of this variable is 36 which answers why your loop has 36 iterations
If you run the apply function against the column :
pd1[0].apply(gen_cusip_checkbit)
The variable that would be sent is just :
912810SE
which should give you the right output .

Python: local, global variables

I am making new program in Python (Mastermind). I have a problem with references of variables:
def user_turn():
try_counter = 1
user_code = []
guessed_code = random_code()
print("Twoja kolej na zgadywanie!")
while try_counter <= max_tries and user_code != guessed_code:
good_number, good_number_and_position = 0, 0
appearance_types_guessing_code = [0 for i in range(types)]
appearance_types_user_code = [0 for i in range(types)]
user_code = input("Próba nr {}: ".format(try_counter))
user_code = list(map(int, str(user_code)))
count_xos()
print_xos()
try_counter += 1
print_result_user_turn()
Body of the function print_xos():
def print_xos():
for i in range(good_number_and_position):
print("x", end='')
for i in range(good_number):
print("o", end='')
print("")
And my problem is that in function print_xos() variables good_number and good_number_and_position are unknown, despite of fact I declared this variables in the while loop in the body of the function user_turn(). How can I solve this problem? I don't want to send the reference as an argument of the function. In my opinion it isn't elegant. Is it possible to do it in another way?
EDIT:
OK, I changed a code a little bit then:
def user_turn():
try_counter = 1
user_code = []
guessed_code = random_code()
appearance_types_guessed_code = [0] * types
how_many_appearance(guessed_code, appearance_types_guessed_code)
print("Twoja kolej na zgadywanie!")
while try_counter <= max_tries and user_code != guessed_code:
good_number, good_number_and_position = 0, 0
appearance_types_user_code = [0] * types
user_code = input("Próba nr {}: ".format(try_counter))
user_code = list(map(int, str(user_code)))
how_many_appearance(user_code, appearance_types_user_code)
print(appearance_types_guessed_code, appearance_types_user_code)
count_xos(guessed_code, appearance_types_guessed_code, user_code, appearance_types_user_code, good_number, good_number_and_position)
print(good_number_and_position, good_number)
print_xos(good_number_and_position, good_number)
try_counter += 1
print_result_user_turn(guessed_code, user_code)
And the body of function count_xos:
def count_xos(guessed_code, appearance_types_guessed_code, user_code, appearance_types_user_code, good_number, good_number_and_position):
for i in range(len(appearance_types_guessed_code)):
good_number += np.min([appearance_types_guessed_code[i], appearance_types_user_code[i]])
for i in range(code_size):
if guessed_code[i] == user_code[i]:
good_number_and_position += 1
good_number -= 1
print(good_number_and_position, good_number)
And I got this output:
RUNDA 1
Twoja kolej na zgadywanie!
Próba nr 1: 0011
[0, 2, 0, 1, 0, 0, 0, 1, 0, 0] [2, 2, 0, 0, 0, 0, 0, 0, 0, 0]
1 1
0 0
You can be certain that function count_xos counts good_number, good_number_and_position counts properly. It should be 1 1, but I don't know why after running the method count_xos, variables good_number_and_position, good_number are not changed?
Your last attempt does not return the numbers so the provided numbers do not carry out into your calling function.
Your code does the equivalent of:
def one(aa,bb):
aa *= 2
bb *= 3
print("In function", aa, bb)
return aa, bb
a = 5
b = 11
one(a,b) # does not reassign returned values - similar to not return anything like yours
print(a,b)
Output:
In function 10 33
5 11
You need to return and reassign the values:
a,b = one(a,b) # reassign returns
print(a,b)
Output:
In function 10 33
10 33
Have a look at Scoping rules - it it best to keep the scope as small as possible and provide data to the function they need.
If you modify things inside function return its new values and reassign them - this is not deeded if you pass a list, they are mutable references and "autoupdate" because you operate through the ref on the data:
# same function used as above
a = 5
b = [11]
one(a,b)
print(a,b)
Output:
In function 10 [11, 11, 11]
5 [11, 11, 11]
If you take a look at the id()s of the variables you can see that altering aa will repoint the name aa to some other id - but a on the outside still points to the original one. Altering the list does not alter the reference-id - it alters the data the ref "points" to:
def one_ids(aa,bb):
print(id(aa),id(bb))
aa *= 3 # modify an integer
bb *= 3 # modify the list
print(id(aa),id(bb))
a = 5
b = [11]
print(id(a),id(b))
one_ids(a,b)
print(id(a),id(b))
Output:
139647789732288 139647790644808 # id of a,b
139647789732288 139647790644808 # id of aa,bb before changing
139647789732**6**08 139647790644808 # id of aa,bb after changing
139647789732288 139647790644808 # id of a,b
You can read further in Function changes list values and not variable values in Python - see if those explanaitions fit you better.

Python - Why are some test cases failing?

So I'm working through problems on hackerrank, I am a beginner in python.
The information about what I'm trying to dois found here: https://www.hackerrank.com/challenges/compare-the-triplets?h_r=next-challenge&h_v=zen
a0,a1,a2 = input().strip().split(' ')
a0,a1,a2 = [int(a0),int(a1),int(a2)]
b0,b1,b2 = input().strip().split(' ')
b0,b1,b2 = [int(b0),int(b1),int(b2)]
a1 = 0
b1 = 0
lst1 = a0,a1,a2
lst2 = b0,b1,b2
for x, y in zip(lst1, lst2):
if x > y:
a1 += 1
if x <y:
b1 += 1
else:
pass
print(a1, b1)
So this works perfectly well.
However, in one of the test cases, the input is
6 8 12
7 9 15
and output should be
0 3
However my code keeps failing it. Why is this so?
I find 2 issues in this.
1. variable names are same. Notice a1 in list and and a1 as a separate Variable.
2. Instead of print you can use '{0} {1}'.format(a1,b1)
Also I would suggest using raw_input() instead of input(), that will help your input treated as a string.
Maybe you need to change varibale name of a1,b1 in your code to some other names.
....
a1 = 0
b1 = 0
...
They will remove input a1/b1 as the same name, I don't see why that needed :)
a0,a1,a2 = [int(a0),int(a1),int(a2)]
b0,b1,b2 = [int(b0),int(b1),int(b2)]

How to toggle between two values?

I want to toggle between two values in Python, that is, between 0 and 1.
For example, when I run a function the first time, it yields the number 0. Next time, it yields 1. Third time it's back to zero, and so on.
Sorry if this doesn't make sense, but does anyone know a way to do this?
Use itertools.cycle():
from itertools import cycle
myIterator = cycle(range(2))
myIterator.next() # or next(myIterator) which works in Python 3.x. Yields 0
myIterator.next() # or next(myIterator) which works in Python 3.x. Yields 1
# etc.
Note that if you need a more complicated cycle than [0, 1], this solution becomes much more attractive than the other ones posted here...
from itertools import cycle
mySmallSquareIterator = cycle(i*i for i in range(10))
# Will yield 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 0, 1, 4, ...
You can accomplish that with a generator like this:
>>> def alternate():
... while True:
... yield 0
... yield 1
...
>>>
>>> alternator = alternate()
>>>
>>> alternator.next()
0
>>> alternator.next()
1
>>> alternator.next()
0
You can use the mod (%) operator.
count = 0 # initialize count once
then
count = (count + 1) % 2
will toggle the value of count between 0 and 1 each time this statement is executed. The advantage of this approach is that you can cycle through a sequence of values (if needed) from 0 - (n-1) where n is the value you use with your % operator. And this technique does not depend on any Python specific features/libraries.
e.g.
count = 0
for i in range(5):
count = (count + 1) % 2
print(count)
gives:
1
0
1
0
1
You may find it useful to create a function alias like so:
import itertools
myfunc = itertools.cycle([0,1]).next
then
myfunc() # -> returns 0
myfunc() # -> returns 1
myfunc() # -> returns 0
myfunc() # -> returns 1
In python, True and False are integers (1 and 0 respectively). You could use a boolean (True or False) and the not operator:
var = not var
Of course, if you want to iterate between other numbers than 0 and 1, this trick becomes a little more difficult.
To pack this into an admittedly ugly function:
def alternate():
alternate.x=not alternate.x
return alternate.x
alternate.x=True #The first call to alternate will return False (0)
mylist=[5,3]
print(mylist[alternate()]) #5
print(mylist[alternate()]) #3
print(mylist[alternate()]) #5
from itertools import cycle
alternator = cycle((0,1))
next(alternator) # yields 0
next(alternator) # yields 1
next(alternator) # yields 0
next(alternator) # yields 1
#... forever
var = 1
var = 1 - var
That's the official tricky way of doing it ;)
Using xor works, and is a good visual way to toggle between two values.
count = 1
count = count ^ 1 # count is now 0
count = count ^ 1 # count is now 1
To toggle variable x between two arbitrary (integer) values,
e.g. a and b, use:
# start with either x == a or x == b
x = (a + b) - x
# case x == a:
# x = (a + b) - a ==> x becomes b
# case x == b:
# x = (a + b) - b ==> x becomes a
Example:
Toggle between 3 and 5
x = 3
x = 8 - x (now x == 5)
x = 8 - x (now x == 3)
x = 8 - x (now x == 5)
This works even with strings (sort of).
YesNo = 'YesNo'
answer = 'Yes'
answer = YesNo.replace(answer,'') (now answer == 'No')
answer = YesNo.replace(answer,'') (now answer == 'Yes')
answer = YesNo.replace(answer,'') (now answer == 'No')
Using the tuple subscript trick:
value = (1, 0)[value]
Using tuple subscripts is one good way to toggle between two values:
toggle_val = 1
toggle_val = (1,0)[toggle_val]
If you wrapped a function around this, you would have a nice alternating switch.
If a variable is previously defined and you want it to toggle between two values, you may use the
a if b else c form:
variable = 'value1'
variable = 'value2' if variable=='value1' else 'value1'
In addition, it works on Python 2.5+ and 3.x
See Expressions in the Python 3 documentation.
Simple and general solution without using any built-in. Just keep the track of current element and print/return the other one then change the current element status.
a, b = map(int, raw_input("Enter both number: ").split())
flag = input("Enter the first value: ")
length = input("Enter Number of iterations: ")
for i in range(length):
print flag
if flag == a:
flag = b;
else:
flag = a
Input:
3 835Output:38383
Means numbers to be toggled are 3 and 8
Second input, is the first value by which you want to start the sequence
And last input indicates the number of times you want to generate
One cool way you can do in any language:
variable = 0
variable = abs(variable - 1) // 1
variable = abs(variable - 1) // 0

Categories