Variable nesting in Python - python

Basically, I need to make my program able to create multiple (unlimited) variables for me, that I will still be able to use manipulate through my code, without me defining them.
I was thinking to have a letter and a number as the variable name, such as a1, and have the program create new variables just adding 1 to the number. So it would create a1 through a30 or so. How would I do this?
My program is going to add polynomials and the variables (or list now) is to separate the different monomials, and since I don't know how many monomials there will be in the polynomial, I needed a way to make the number flexible so I have an exact amout of spaces for the monomials, no extras, and no less.
Here's the code:
# Sample polynomial set to x, the real code will say x = (raw_input("Enter a Polynomial")).
x = '(5xx + 2y + 2xy)+ (4xx - 1xy)'
# Isdigit command set to 't' to make the code easier to write.
t = str.isdigit
# Defining v for later use.
v = 0
# Defining 'b' which will be the index number that the program will look at.
b = 1
# Creating 'r' to parse the input to whatever letter is next.
r = x [b]
# Defining n which will be used later to tell if the character is numeric.
n = 0
# Defining r1 which will hold one of the monomials, ( **will be replaced with a list**)
#This was the variable in question.
r1 = ''
# Setting 'p' to evaluate if R is numeric ( R and T explained above).
p = t(r)
# Setting 'n' to 1 or 0 to replace having to write True or False later.
if p == True:
n = 1
else:
n = 0
# Checking if r is one of the normal letters used in Algebra, and adding it to a variable
if r == 'x':
v = 'x'
c = 1
elif r == 'y':
v = 'y'
c = 1
elif r == 'z':
v = 'z'
c = 1
# If the character is a digit, set c to 0, meaning that the program has not found a letter yet (will be used later in the code).
elif n == 1:
v = r
c = 0
# Adding what the letter has found to a variable (will be replaced with a list).
r1 = r1 + v
b = b + 1
I will eventually make this a loop.
I added comments to the code so it's more understandable.

Essentially, you are trying to programmatically, dynamically modify the heap space where the variables live. I really do not think this is possible. If it is, it is very obscure.
I do understand where you are coming from. When I was first learning to program I had thought to solve problems in ways that would require such "dynamically created" variables. The solution really is to recognize what kind of (collection) data structure fits your needs.
If you want variables a1 through a30, create a list a. Then a1 would be a[1], a30 would be a[30]. It is a little different to write, but it should give you the behavior you need.

I spent at least five minutes trying to think why you would want to do this in the first place, until I decided I could actually write the code in less than five minutes, and hoping that in return you'd tell us why you want to do this.
Here's the code:
def new(value):
highest = -1
for name in globals():
if name.startswith('a'):
try:
number = int(name[1:])
except:
continue
if number > highest:
highest = number
globals()['a%d' % (highest + 1, )] = value
new("zero")
new("one")
new("two")
print a2 # prints two

Related

How can I count sequences that meet these constraints?

I am trying to count permutations of a sequence of I and O symbols, representing e.g. people entering (I for "in") and leaving (O for "out") a room. For a given n many I symbols, there should be exactly as many O symbols, giving a total length of 2*n for the sequence. Also, at any point in a valid permutation, the number of O symbols must be less than or equal to the number of I symbols (since it is not possible for someone to leave the room when it is empty).
Additionally, I have some initial prefix of I and O symbols, representing people who previously entered or left the room. The output should only count sequences starting with that prefix.
For example, for n=1 and an initial state of '', the result should be 1 since the only valid sequence is IO; for n=3 and an initial state of II, the possible permutations are
IIIOOO
IIOIOO
IIOOIO
for a result of 3. (There are five ways for three people to enter and leave the room, but the other two involve the first person leaving immediately.)
I'm guessing the simplest way to solve this is using itertools.permutations. This is my code so far:
n=int(input()) ##actual length will be 2*n
string=input()
I_COUNT=string.count("I")
O_COUNT=string.count("O")
if string[0]!="I":
sys.exit()
if O_COUNT>I_COUNT:
sys.exit()
perms = [''.join(p) for p in permutations(string)]
print(perms)
the goal is to get the permutation for whatever is left out of the string and append it to the user's input, so how can I append user's input to the remaining length of the string and get the count for permutation?
#cache
def count_permutations(ins: int, outs: int):
# ins and outs are the remaining number of ins and outs to process
assert outs >= ins
if ins == 0 :
# Can do nothing but output "outs"
return 1
elif outs == ins:
# Your next output needs to be an I else you become unbalanced
return count_permutations(ins - 1, outs)
else:
# Your. next output can either be an I or an O
return count_permutations(ins - 1, outs) + count_permutations(ins, outs - 1)
If, say you have a total of 5 Is and 5 Os, and you've already output one I, then you want: count_permutations(4, 5).
I'm guessing the simplest way to solve this is using itertools.permutations
Sadly, this will not be very helpful. The problem is that itertools.permutations does not care about the value of the elements it's permuting; it treats them as all distinct regardless. So if you have 6 input elements, and ask for length-6 permutations, you will get 720 results, even if all the inputs are the same.
itertools.combinations has the opposite issue; it doesn't distinguish any elements. When it selects some elements, it only puts those elements in the order they initially appeared. So if you have 6 input elements and ask for length-6 combinations, you will get 1 result - the original sequence.
Presumably what you wanted to do is generate all the distinct ways of arranging the Is and Os, then take out the invalid ones, then count what remains. This is possible, and the itertools library can help with the first step, but it is not straightforward.
It will be simpler to use a recursive algorithm directly. The general approach is as follows:
At any given time, we care about how many people are in the room and how many people must still enter. To handle the prefix, we simply count how many people are in the room right now, and subtract that from the total number of people in order to determine how many must still enter. I leave the input handling as an exercise.
To determine that count, we count up the ways that involve the next action being I (someone comes in), plus the ways that involve the next action being O (someone leaves).
If everyone has entered, there is only one way forward: everyone must leave, one at a time. This is a base case.
Otherwise, it is definitely possible for someone to come in. We recursively count the ways for everyone else to enter after that; in the recursive call, there is one more person in the room, and one fewer person who must still enter.
If there are still people who have to enter, and there is also someone in the room right now, then it is also possible for someone to leave first. We recursively count the ways for others to enter after that; in the recursive call, there is one fewer person in the room, and the same number who must still enter.
This translates into code fairly directly:
def ways_to_enter(currently_in, waiting):
if waiting == 0:
return 1
result = ways_to_enter(currently_in + 1, waiting - 1)
if currently_in > 0:
result += ways_to_enter(currently_in - 1, waiting)
return result
Some testing:
>>> ways_to_enter(0, 1) # n = 1, prefix = ''
1
>>> ways_to_enter(2, 1) # n = 3, prefix = 'II'; OR e.g. n = 4, prefix = 'IIOI'
3
>>> ways_to_enter(0, 3) # n = 3, prefix = ''
5
>>> ways_to_enter(0, 14) # takes less than a second on my machine
2674440
We can improve the performance for larger values by decorating the function with functools.cache (lru_cache prior to 3.9), which will memoize results of the previous recursive calls. The more purpose-built approach is to use dynamic programming techniques: in this case, we would initialize 2-dimensional storage for the results of ways_to_enter(x, y), and compute those values one at a time, in such a way that the values needed for the "recursive calls" have already been done earlier in the process.
That direct approach would look something like:
def ways_to_enter(currently_in, waiting):
# initialize storage
results = [[0] * currently_in for _ in waiting]
# We will iterate with `waiting` as the major axis.
for w, row in enumerate(results):
for c, column in enumerate(currently_in):
if w == 0:
value = 1
else:
value = results[w - 1][c + 1]
if c > 0:
value += results[w][c - 1]
results[w][c] = value
return results[-1][-1]
The product() function from itertools will allow you to generate all the possible sequences of 'I' and 'O' for a given length.
From that list, you can filter by the sequences that start with the user-supplied start_seq.
From that list, you can filter by the sequences that are valid, given your rules of the number and order of the 'I's and 'O's:
from itertools import product
def is_valid(seq):
'''Evaluates a sequence I's and O's following the rules that:
- there cannot be more outs than ins
- the ins and outs must be balanced
'''
_in, _out = 0, 0
for x in seq:
if x == 'I':
_in += 1
else:
_out += 1
if (_out > _in) or (_in > len(seq)/2):
return False
return True
# User inputs...
start_seq = 'II'
assert start_seq[0] != 'O', 'Starting sequence cannot start with an OUT.'
n = 3
total_len = n*2
assert len(start_seq) < total_len, 'Starting sequence is at least as big as total number, nothing to iterate.'
# Calculate all possible sequences that are total_len long, as tuples of 'I' and 'O'
seq_tuples = product('IO', repeat=total_len)
# Convert tuples to strings, e.g., `('I', 'O', 'I')` to `'IOI'`
sequences = [''.join(seq_tpl) for seq_tpl in seq_tuples]
# Filter for sequences that start correctly
sequences = [seq for seq in sequences if seq.startswith(start_seq)]
# Filter for valid sequences
sequences = [seq for seq in sequences if is_valid(seq)]
print(sequences)
and I get:
['IIIOOO', 'IIOIOO', 'IIOOIO']
Not very elegant perhaps but this certainly seems to fulfil the brief:
from itertools import permutations
def isvalid(start, p):
for c1, c2 in zip(start, p):
if c1 != c2:
return 0
n = 0
for c in p:
if c == 'O':
if (n := n - 1) < 0:
return 0
else:
n += 1
return 1
def calc(n, i):
s = i + 'I' * (n - i.count('I'))
s += 'O' * (n * 2 - len(s))
return sum(isvalid(i, p) for p in set(permutations(s)))
print(calc(3, 'II'))
print(calc(3, 'IO'))
print(calc(3, 'I'))
print(calc(3, ''))
Output:
3
2
5
5
def solve(string,n):
countI =string.count('I')
if countI==n:
return 1
countO=string.count('O')
if countO > countI:
return 0
k= solve(string + 'O',n)
h= solve(string + 'I',n)
return k+h
n= int(input())
string=input()
print(solve(string,n))
This is a dynamic programming problem.
Given the number of in and out operations remaining, we do one of the following:
If we're out of either ins or outs, we can only use operations of the other type. There is only one possible assignment.
If we have an equal number of ins or outs, we must use an in operation according to the constraints of the problem.
Finally, if we have more ins than outs, we can perform either operation. The answer, then, is the sum of the number of sequences if we choose to use an in operation plus the number of sequences if we choose to use an out operation.
This runs in O(n^2) time, although in practice the following code snippet can be made faster using a 2D-list rather than the cache annotation (I've used #cache in this case to make the recurrence easier to understand).
from functools import cache
#cache
def find_permutation_count(in_remaining, out_remaining):
if in_remaining == 0 or out_remaining == 0:
return 1
elif in_remaining == out_remaining:
return find_permutation_count(in_remaining - 1, out_remaining)
else:
return find_permutation_count(in_remaining - 1, out_remaining) + find_permutation_count(in_remaining, out_remaining - 1)
print(find_permutation_count(3, 3)) # prints 5
The number of such permutations of length 2n is given by the n'th Catalan number. Wikipedia gives a formula for Catalan numbers in terms of central binomial coefficients:
from math import comb
def count_permutations(n):
return comb(2*n,n) // (n+1)
for i in range(1,10):
print(i, count_permutations(i))
# 1 1
# 2 2
# 3 5
# 4 14
# 5 42
# 6 132
# 7 429
# 8 1430
# 9 4862

Longest sequence of equal numbers in python

I tried to generate the longest sequence of equal numbers in python, but it doesn't work
def lista_egale(lst1 = input("numbers go here ")):
l = 0
lst1 = []
maxi = -9999
prev_one = None
lmax = -9999
for current in lst1:
if prev_one == current:
l += 1
else:
l = 1
if l > lmax:
lmax = l
maxi = current
prev_one = current
print("longest sequence is ", lmax, " and ", maxi)
lista_egale()
Input:
1 2 2 2 2 3 4 5 6 2 2 2
Expected Output:
longest sequence is 4 and 2
I was going to write up the same concern about your default argument, but that would at least work correctly the first time it is called. This function does not. Everyone jumped on that common problem, and failed to notice the next line. Let's look another look at this abridged version of your code:
irrelevant = input("numbers go here ")
def lista_egale(lst1 = irrelevant):
# while it is true that your default argument is bad,
# that doesn't matter because of this next line:
lst1 = []
for current in lst1:
# unreachable code
pass
To clarify, since your reply indicates this is not clear enough, it doesn't matter what value was passed in to lst1 if you immediately overwrite it with an empty list.
(for others reading this:) Separating out what I labeled "irrelevant" is not quite identical, but I'm trying to point out that the input was overwritten.
I don't think this function should take user input or have a default argument at all. Let it be a function with one job, and just pass it the data to work on. User input can be collected elsewhere.
Based on Barmar's note, and the principle of using only unmutable default values, your code should look something more like this:
def lista_egale(inp1 = None):
if not inp1:
inp1 = input("numbers go here ")
# optionally do some error checking for nonnumerical characters here
lst1 = [int(i) for i in inp1.split(" ")]
# rest of your code here
lista_egale()
Basically, input returns a string value, and you need to convert it into a list of integers first before you start working on it.
You can swap out the list comprehension for map(int, inp1.split(" ")) as it will do the same (but you can't iterate through a map more than once unless you wrap it in a list() function first).
Secondly, avoid setting mutable default arguments as (in short) can lead to weird results when rerunning the same function multiple times.

My python recursive function won't return and exceeds maximum recursive depth

I simply do not understand why this is not returning the value and stopping the recursion. I have tried everything but it seems to just keep on going no matter what I do. I am trying to get the program to get the loop to compare the first two values of the list if they are the same return that it was the first value. If they were not, add the first and second values of each list and compare, etc etc until it reaches the end of the list. If the sum of the values in each list never equal each other at any point then return 0.
It is supposed to take three inputs:
A single integer defining the length of the next two inputs
First set of input data
Second set of input data
Ex input
3
1 3 3
2 2 2
It should output a single number. In the case of the example data, it should output 2 because the sum of the lists equalled at the second value.
N = int(input())
s1 = input().split()
s2 = input().split()
count = 0
def func1(x,y):
if x == y:
return(count)
elif (N - 1) == count:
return(0)
else:
count + 1
return(func1(x + int(s1[count]), y + int(s2[count])))
days = func1(int(s1[0]),int(s2[0]))
print(days)
I am sorry in advance if I really messed up the formatting or made some dumb mistake, I am pretty new to programming and I have never posted on here before. Thanks in advance :)
The problem is that you never actually update the variable count. However, just writing:
count += 1
is not going to work either without declaring the variable global:
def func1(x, y):
global count
....
That said, global variables increase code complexity and break re-enterability, i.e. the same function can no longer be called twice, not to mention about concurrency. A much cleaner way is to make count a function argument, it will look like this (the code not tested and is here for illustration only):
N = int(input())
s1 = [int(c) for c in input().split()]
s2 = [int(c) for c in input().split()]
def func1(x, y, count=0):
if x == y:
return count
elif count == N - 1:
return 0
else:
return(func1(x + s1[count], y + s2[count]), count + 1)
days = func1(int(s1[0]),int(s2[0]))
print(days)
To answer "How would you go about solving this problem then" – If I understood the problem correctly, the aim is to find the index where the "running total" of the two lists is the same. If so,
def func1(s1, s2):
total_a = 0
total_b = 0
for i, (a, b) in enumerate(zip(s1, s2)):
total_a += a
total_b += b
if total_a == total_b:
return i
return 0
print(func1([1, 3, 3], [2, 2, 2]))
does the trick. (I've elided the input bits here – this function just works with two lists of integers.)

why my return function is not working python

initialValues = input('Please enter a space separated set of values for y, h and g(0): ')
values = []
values.append(initialValues)
theValues = []
for item in values:
item = item.split(' ')
for index in range(len(item)):
item[index] = int(item[index])
theValues.append(item)
y = theValues[0][0]
h = theValues[0][1]
g0 = theValues[0][2]
def Sumrecur(y,h,g0):
if y == 0 :
return g0
else:
sum = 0
for k in range(1,y):
sum = sum + Sumrecur(k,h,g0)*h
return sum
Sumrecur(y,h,g0)
this is a function i'm currently working on. I'm confused as the return sum command doesn't work. Is there anything wrong with the code?? Sorry it might sound silly to some of you but I really don't know how to fix this.
thanks before!
Once you've gone 1 recursion deep you need to return multiple times to actually return the value. Basically you've returned the value to the last recursion but this isn't the original one you called so there will be no output. Maybe write to a global variable or print the value instead.
TL;DR :
I would try using range(0,y) in your for loop.
BREAKDOWN:
Your recursion depends on the value of y and only ends whenever y equals 0 .
Lets see how the recursions are called using an example
STEP 1
Sumrecur(3,1,1) will call Sumrecur(1,1,1) and Sumrecur(2,1,1)
STEP 2a :
Sumrecur(1,1,1) calls nothing
STEP 2b :
Sumrecur(2,1,1) calls Sumrecur(1,1,1)
STEP 3:
Sumrecur(1,1,1) calls nothing
You see what the issue is ? The value of y never equals 0 , so it never enters the
if y == 0 :
return g0
I would try using range(0,y) in your for loop.

Read Bits for definded length at defined position

I have a bitstring.Bitarray and want to read from a certain position to another position.
I have the int variable length in a for loop, so for example I have:
length = 2
and my Bitarray looks something like:
msgstr = bitstring.BitArray(0b11110011001111110)
id = bitstring.BitArray()
m = 0
while 5 != m:
/////////////
Length changes in value part of Code
/////////////
x = 0
if m == 0:
while length != x:
id.append = msgstr[x] #msgstr is the BitArray that needs to be read
x = x + 1
m = m + 1
I then want to read the first two bits and convert them into an int, so that I have:
id == 3
And for the next round when length has changed in value it should start from the third bit etc.
The code inside your loop only does anything if m == 0, but then you increment m, so m is only 0 the first time through the loop. The rest of the times you go through your loop, it doesn't seem to actually be doing anything.
Also, where you say
id.append = msgstr[x]
you probably actually want
id.append(msgstr[x])
It also seems like you might benefit from using Python's slice notation.
I do not understand exactly what you goal is but do you had a look at https://wiki.python.org/moin/BitManipulation ?

Categories