Funny behaviour of my recursive function - python

t = 8
string = "1 2 3 4 3 3 2 1"
string.replace(" ","")
string2 = [x for x in string]
print string2
for n in range(t-1):
string2.remove(' ')
print string2
def remover(ca):
newca = []
print len(ca)
if len(ca) == 1:
return ca
else:
for i in ca:
newca.append(int(i) - int(min(ca)))
for x in newca:
if x == 0:
newca.remove(0)
print newca
return remover(newca)
print (remover(string2))
It's supposed to be a program that takes in a list of numbers, and for every number in the list it subtracts from it, the min(list). It works fine for the first few iterations but not towards the end. I've added print statements here and there to help out.
EDIT:
t = 8
string = "1 2 3 4 3 3 2 1"
string = string.replace(" ","")
string2 = [x for x in string]
print len(string2)
def remover(ca):
newca = []
if len(ca) == 1: return()
else:
for i in ca:
newca.append(int(i) - int(min(ca)))
while 0 in newca:
newca.remove(0)
print len(newca)
return remover(newca)
print (remover(string2))

for x in newca:
if x == 0:
newca.remove(0)
Iterating over a list and removing things from it at the same time can lead to strange and unexpected behvaior. Try using a while loop instead.
while 0 in newca:
newca.remove(0)
Or a list comprehension:
newca = [item for item in newca if item != 0]
Or create yet another temporary list:
newnewca = []
for x in newca:
if x != 0:
newnewca.append(x)
print newnewca
return remover(newnewca)

(Not a real answer, JFYI:)
Your program can be waaay shorter if you decompose it into proper parts.
def aboveMin(items):
min_value = min(items) # only calculate it once
return differenceWith(min_value, items)
def differenceWith(min_value, items):
result = []
for value in items:
result.append(value - min_value)
return result
The above pattern can, as usual, be replaced with a comprehension:
def differenceWith(min_value, items):
return [value - min_value for value in items]
Try it:
>>> print aboveMin([1, 2, 3, 4, 5])
[0, 1, 2, 3, 4]
Note how no item is ever removed, and that data are generally not mutated at all. This approach helps reason about programs a lot; try it.

So IF I've understood the description of what you expect,
I believe the script below would result in something closer to your goal.
Logic:
split will return an array composed of each "number" provided to raw_input, while even if you used the output of replace, you'd end up with a very long number (you took out the spaces that separated each number from one another), and your actual split of string splits it in single digits number, which does not match your described intent
you should test that each input provided is an integer
as you already do a print in your function, no need for it to return anything
avoid adding zeros to your new array, just test first
string = raw_input()
array = string.split()
intarray = []
for x in array:
try:
intarray.append(int(x))
except:
pass
def remover(arrayofint):
newarray = []
minimum = min(arrayofint)
for i in array:
if i > minimum:
newarray.append(i - minimum)
if len(newarray) > 0:
print newarray
remover(newarray)
remover(intarray)

Related

How can I assign positives and negatives to a string?

I'm trying to create this code so that when variable J is present, it is a positive number, but if H is present, it is a negative number. Here is my code.
record = ['1J2H']
def robot_location(record: str):
if J in record:
sum()
if H in record:
** I dont know how to subtract them**
print(robot_location(record)
So if record = [1J2H] then the output should be ((+1)+(-2)) = -1 should be the output... how can I do that?? Somebody pls help explain this.
You need to iterate over string inside list, check char by char and asume thats always length of string will be odd
record = ['1J2H']
def robot_location(record: str):
total = 0
aux_n = 0
for a in record:
if a.isnumeric():
aux_n = int(a)
else:
if a == 'H':
total = total + aux_n*-1
else:
total = total + aux_n
aux_n = 0
return total
print(robot_location(record[0]))
Here is a concise way to do this via a list comprehension:
record = '1J2H'
nums = re.findall(r'\d+[JH]', record) # ['1J', '2H']
output = sum([int(x[:-1]) if x[-1] == 'J' else -1*int(x[:-1]) for x in nums])
print(output) # -1
One way to do that is by using iter and converting the string into an iterable, that allows to use next which moves the iteration to the next item meaning that if one simply iterates over it it will get moved to the next item and then if one uses next it will return the current value where the "pointer"? is and move it to the next value so the next iteration with a for loop (list comprehension in this case) will get the next value, meaning that the loop will return only the numbers while next will return only the letters:
lst = ['1J2H']
def robot_location(record: str):
record = iter(record)
numbers = [int(i) if next(record) == 'J' else -int(i) for i in record]
return sum(numbers)
print(robot_location(lst[0]))
You could modify a string like s = '1J2H' to '1+2*-1+0' and let Python evaluate it:
result = eval(s.replace('J', '+').replace('H', '*-1+') + '0')

Changing version number to single digits python

I have a version number in a file like this:
Testing x.x.x.x
So I am grabbing it off like this:
import re
def increment(match):
# convert the four matches to integers
a,b,c,d = [int(x) for x in match.groups()]
# return the replacement string
return f'{a}.{b}.{c}.{d}'
lines = open('file.txt', 'r').readlines()
lines[3] = re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, lines[3])
I want to make it so if the last digit is a 9... then change it to 0 and then change the previous digit to a 1. So 1.1.1.9 changes to 1.1.2.0.
I did that by doing:
def increment(match):
# convert the four matches to integers
a,b,c,d = [int(x) for x in match.groups()]
# return the replacement string
if (d == 9):
return f'{a}.{b}.{c+1}.{0}'
elif (c == 9):
return f'{a}.{b+1}.{0}.{0}'
elif (b == 9):
return f'{a+1}.{0}.{0}.{0}'
Issue occurs when its 1.1.9.9 or 1.9.9.9. Where multiple digits need to rounded. How can I handle this issue?
Use integer addition?
def increment(match):
# convert the four matches to integers
a,b,c,d = [int(x) for x in match.groups()]
*a,b,c,d = [int(x) for x in str(a*1000 + b*100 + c*10 + d + 1)]
a = ''.join(map(str,a)) # fix for 2 digit 'a'
# return the replacement string
return f'{a}.{b}.{c}.{d}'
If your versions are never going to go beyond 10, it is better to just convert it to an integer, increment it and then convert back to a string.
This allows you to go up to as many version numbers as you require and you are not limited to thousands.
def increment(match):
match = match.replace('.', '')
match = int(match)
match += 1
match = str(match)
output = '.'.join(match)
return output
Add 1 to the last element. If it's more than 9, set it to 0 and do the same for the previous element. Repeat as necessary:
import re
def increment(match):
# convert the four matches to integers
g = [int(x) for x in match.groups()]
# increment, last one first
pos = len(g)-1
g[pos] += 1
while pos > 0:
if g[pos] > 9:
g[pos] = 0
pos -= 1
g[pos] += 1
else:
break
# return the replacement string
return '.'.join(str(x) for x in g)
print (re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, '1.8.9.9'))
print (re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, '1.9.9.9'))
print (re.sub(r"\b(\d+)\.(\d+)\.(\d+)\.(\d+)\b", increment, '9.9.9.9'))
Result:
1.9.0.0
2.0.0.0
10.0.0.0

Assertion error, eventhough my return value is the same

def interleave(s1,s2): #This function interleaves s1,s2 together
guess = 0
total = 0
while (guess < len(s1)) and (guess < len(s2)):
x = s1[guess]
y = s2[guess]
m = x + y
print ((m),end ="")
guess += 1
if (len(s1) == len(s2)):
return ("")
elif(len(s1) > len(s2)):
return (s1[guess:])
elif(len(s2) > len(s1)):
return (s2[guess:])
print (interleave("Smlksgeneg n a!", "a ie re gsadhm"))
For some reason, my test function gives an assertion error eventhough the output is the same as the code below.
Eg - "Smlksgeneg n a!", "a ie re gsadhm" returns "Sam likes green eggs and ham!"
but an assertion error still comes out
def testInterleave():
print("Testing interleave()...", end="")
assert(interleave("abcdefg", "abcdefg")) == ("aabbccddeeffgg")
assert(interleave("abcde", "abcdefgh") == "aabbccddeefgh")
assert(interleave("abcdefgh","abcde") == "aabbccddeefgh")
assert(interleave("Smlksgeneg n a!", "a ie re gsadhm") ==
"Sam likes green eggs and ham!")
assert(interleave("","") == "")
print("Passed!")
testInterleave()
You are confusing what is printed by interleave() from what is returned by it. The assert is testing the returned value. For example, when s1 and s2 are the same length, your code prints the interleave (on the print((m),end="") line) but returns an empty string (in the line return ("")
If you want interleave to return the interleaved string, you need to collect the x and y variables (not very well named if they are always holding characters) into a single string and return that.
The problem is that your function just prints the interleaved portion of the resulting string, it doesn't return it, it only returns the tail of the longer string.
Here's a repaired and simplified version of your code. You don't need to do those if... elif tests. Also, your code has a lot of superfluous parentheses (and one misplaced parenthesis), which I've removed.
def interleave(s1, s2):
''' Interleave strings s1 and s2 '''
guess = 0
result = ""
while (guess < len(s1)) and (guess < len(s2)):
x = s1[guess]
y = s2[guess]
result += x + y
guess += 1
return result + s1[guess:] + s2[guess:]
def testInterleave():
print("Testing interleave()...", end="")
assert interleave("abcdefg", "abcdefg") == "aabbccddeeffgg"
assert interleave("abcde", "abcdefgh") == "aabbccddeefgh"
assert interleave("abcdefgh","abcde") == "aabbccddeefgh"
assert (interleave("Smlksgeneg n a!", "a ie re gsadhm")
== "Sam likes green eggs and ham!")
assert interleave("", "") == ""
print("Passed!")
print(interleave("Smlksgeneg n a!", "a ie re gsadhm"))
testInterleave()
output
Sam likes green eggs and ham!
Testing interleave()...Passed!
Here's a slightly improved version of interleave. It uses a list to store the result, rather than using repeated string concatenation. Using lists to build string like this is a common Python practice because it's more efficient than repeated string concatenation using + or +=; OTOH,+ and += on strings have been optimised so that they're fairly efficient for short strings (up to 1000 chars or so).
def interleave(s1, s2):
result = []
i = 0
for i, t in enumerate(zip(s1, s2)):
result.extend(t)
i += 1
result.extend(s1[i:] + s2[i:])
return ''.join(result)
That i = 0 is necessary in case either s1 or s2 are empty strings. When that happens the for loop isn't entered and so i won't get assigned a value.
Finally, here's a compact version using a list comprehension and the standard itertools.zip_longest function.
def interleave(s1, s2):
return ''.join([u+v for u,v in zip_longest(s1, s2, fillvalue='')])

formatting list to convert into string

Here is my question
count += 1
num = 0
num = num + 1
obs = obs_%d%(count)
mag = mag_%d%(count)
while num < 4:
obsforsim = obs + mag
mylist.append(obsforsim)
for index in mylist:
print index
The above code gives the following results
obs1 = mag1
obs2 = mag2
obs3 = mag3
and so on.
obsforrbd = parentV = {0},format(index)
cmds.dynExpression(nPartilce1,s = obsforrbd,c = 1)
However when i run the code above it only gives me
parentV = obs3 = mag3
not the whole list,it only gives me the last element of the list why is that..??
Thanks.
I'm having difficulty interpreting your question, so I'm just going to base this on the question title.
Let's say you have a list of items (they could be anything, numbers, strings, characters, etc)
myList = [1,2,3,4,"abcd"]
If you do something like:
for i in myList:
print(i)
you will get:
1
2
3
4
"abcd"
If you want to convert this to a string:
myString = ' '.join(myList)
should have:
print(myString)
>"1 2 3 4 abcd"
Now for some explanation:
' ' is a string in python, and strings have certain methods associated with them (functions that can be applied to strings). In this instance, we're calling the .join() method. This method takes a list as an argument, and extracts each element of the list, converts it to a string representation and 'joins' it based on ' ' as a separator. If you wanted a comma separated list representation, just replace ' ' with ','.
I think your indentations wrong ... it should be
while num < 4:
obsforsim = obs + mag
mylist.append(obsforsim)
for index in mylist:
but Im not sure if thats your problem or not
the reason it did not work before is
while num < 4:
obsforsim = obs + mag
#does all loops before here
mylist.append(obsforsim) #appends only last
The usual pythonic way to spit out a list of numbered items would be either the range function:
results = []
for item in range(1, 4):
results.append("obs%i = mag_%i" % (item, item))
> ['obs1 = mag_1', 'obs2 = mag_2', 'ob3= mag_3']
and so on (note in this example you have to pass in the item variable twice to get it to register twice.
If that's to be formatted into something like an expression you could use
'\n'.join(results)
as in the other example to create a single string with the obs = mag pairs on their own lines.
Finally, you can do all that in one line with a list comprehension.
'\n'.join([ "obs%i = mag_%i" % (item, item) for item in range (1, 4)])
As other people have pointed out, while loops are dangerous - its easier to use range

why the output is not good in some cases?

i feel stupid and don't know why the output is not good in some cases.
here is the output (at the end)
it sould find the first sub string in given string for example:
sim('banan','na') -> 'na'
def rev (str):
rev_str=''
i = len(str)-1;
while (i >= 0):
rev_str += str[i];
i = i-1;
return rev_str;
######################################
def sim (str,sub):
sub_len = len (sub);
start = str.index(sub);
rev_str = rev(str)
rev_sub = rev(sub)
if (start ==0):
start =1;
end = start + rev_str.index(rev_sub,start-1);
ret_val = ''
print start , end
for n in range (start,end):
ret_val += str[n];
return ret_val;
print sim('abcdef', 'abc')
print sim('abcdef', 'bc')
print sim('banana', 'na')
the output :
1 4
bcd
1 4
bcd
2 4
na
def sim(haystack, needle):
if needle in haystack:
return needle
If you want indices:
def sim(haystack, needle):
index = haystack.index(needle) # throws ValueError when not found
return (index, index + len(needle))
I agree with Cat's solution. FWIW, you probably want to study a bit about slice syntax. If you're doing string manipulation, slices are a basic tool. I don't see from your code why you wanted to reverse your string, but if you must, try this:
my_string = "abcdefg"
reversed = my_string[::-1] # here's the slice magic
print(reversed)

Categories