196 algorithm with optional inputs in function - python

what I am trying to do:
If the user specifies return_length=True when calling your function, it should return one plus the number of steps the algorithm required to reach a palindromic number. For example, with an input of 5280 and return_length=True, your function should return 4 (Note that this is the total number of entries in the sequence [5280, 6105, 11121, 23232]). With an input of 11, for example, the function should return 1 because it is already a palindromic number.
If the user did not specify return_length or specified return_length=False, your function should return the palindromic number at which the algorithm terminates. For example, with an input of 5280, the algorithm should return 23232 (an integer, not a string). Similarly, with an input of 89, it should return the integer 8813200023188.
Some background on the 196 algorithm:
Take any positive integer of two digits or more, reverse the digits, and add to the original number. This is the operation of the reverse-then-add sequence. Now repeat the procedure with the sum so obtained until a palindromic number is obtained. This procedure quickly produces palindromic numbers for most integers. For example, starting with the number 5280 produces the sequence 5280, 6105, 11121, 23232. The end results of applying the algorithm to 1, 2, 3, ... are 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 11, 33, 44, 55, 66, 77, 88, 99, 121, ... (Sloane's A033865). The value for 89 is especially large, being 8813200023188. (from http://mathworld.wolfram.com/196-Algorithm.html)
What I have so far:
def alg196(x, y = false):
if y==False:
while x == x[::-1]:
x==x+x[::-1]
return x
else:
seq = [x]
while x == x[::-1]:
x==x+x[::-1]
seq.append(x)
return seq
I get the error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "_sage_input_36.py", line 10, in <module>
exec compile(u"print _support_.syseval(python, u'alg196(34)', __SAGE_TMP_DIR__)" + '\n', '', 'single')
File "", line 1, in <module>
File "/sagenb/sage_install/sage-5.3-sage.math.washington.edu-x86_64-Linux/devel/sagenb-git/sagenb/misc/support.py", line 487, in syseval
return system.eval(cmd, sage_globals, locals = sage_globals)
File "/sagenb/sage_install/sage-5.3-sage.math.washington.edu-x86_64-Linux/local/lib/python2.7/site-packages/sage/misc/python.py", line 56, in eval
eval(z, globals)
File "", line 1, in <module>
File "", line 3, in alg196
TypeError: 'int' object has no attribute '__getitem__'
I am not sure how to fix this problem or the error exactly.
Taking some of the information for the answers i have this new code:
def alg196(x, y = false):
if y==False:
while str(x) == str(x)[::-1]:
x=str(x)+str(x)[::-1]
return x
else:
seq = [x]
while str(x) == str(x)[::-1]:
x = str(x)+str(x)[::-1]
seq.append(x)
return seq
But is still do not get the palindromic number for or the sequence to the palindromic number..

x[::-1] does not work on a number:
>>> 42[::-1]
TypeError: 'int' object has no attribute '__getitem__'
You need to convert it to a string, reverse it, then convert it back to an int:
>>> int(str(42)[::-1])
24
Secondly, the line
x==x+x[::-1]
does absolutely nothing. Don't confuse = and ==

something like this:
def algo(r,ret_len=None):
count=0
while 1:
r=str(r)
if r==r[::-1]:
break
else:
count+=1
r=int(r)+int(r[::-1])
return count+1 if ret_len else r
print (algo(5280,True))
print (algo(5280))
print (algo(89,True))
print (algo(89))
output:
4
23232
25
8813200023188

You can't get a 'slice' of an integer. You need to convert it to a string, first. x[::-1] <-- this operation is illegal if x is an integer.
Incidentally, this would be better written as a few functions-- functions that perform the calculations, and a function that runs functions while under a certain constraint, and takes in the return_length=True argument.
def reverse(n):
return int(str(n)[::-1])
def is_palindrome(n):
return str(n) == str(n)[::-1]
def alg196(n, return_length=False):
results = [n]
while not is_palindrome(results[-1]):
results.append(n + reverse(n))
n = results[-1]
return results[-1] if not return_length else len(results)
edit
A slightly quicker variation based on Ashwini Chaudhary's code. The above version produces a list of results, it's nice if you want to do something with the intermediate numbers. But, I think the following function is the best compromise between readability and speed. I have no idea why he starts with count=0 though.
def alg196(n, return_length=False):
count = 1
while not is_palindrome(n):
n = n + reverse(n)
count += 1
return count if return_length else n

Related

ValueError: invalid literal for int() with base 10: '' *Codewars

I'm trying to solve an an exercise on Codewars:
Given an array of integers of any length, return an array that has 1
added to the value represented by the array.
the array can't be empty
only non-negative, single digit integers are allowed
Return nil (or your language's equivalent) for invalid inputs.
Examples
For example the array [2, 3, 9] equals 239, adding one would return
the array [2, 4, 0].
[4, 3, 2, 5] would return [4, 3, 2, 6]
test.assert_equals(up_array([2,3,9]), [2,4,0])
test.assert_equals(up_array([4,3,2,5]), [4,3,2,6])
test.assert_equals(up_array([1,-9]), None)
and I have written the code:
def up_array(arr):
print(arr)
strings = ''
for integer in arr:
if integer < 0 or integer >= 10:
return None
else:
strings += str(integer)
a_string = "".join(strings)
ints = int(a_string) + 1
to_string = str(ints)
return [int(x) for x in to_string]
It passed all of the tests, but it raises an error:
Traceback (most recent call last):
File "tests.py", line 15, in <module>
test.assert_equals(up_array([]), None);
File "/workspace/default/solution.py", line 11, in up_array
ints = int(a_string) + 1
ValueError: invalid literal for int() with base 10: ''
I don't understand why the code raises this error. Thanks
The exception you report makes sense only if arr is empty. That's an "invalid" input, but that doesn't mean it won't be given to you, only that you're not expected to give a normal response (you need to return None).
I suggest adding a check at the top of your function:
if not arr: # empty list
return None
Try this:
def up_array(arr):
num = 1 + int(''.join(str(ele) for ele in arr))
return [int(i) for i in str(num)]
print(up_array([2, 3, 9])) returns [2, 4, 0].
You can also add the if statement from Blckknght's answer at the beginning if you want.

*args in recursion: TypeError: unsupported operand type(s) for +: 'int' and 'tuple'

I am learning python. trying to use take *args as parameter in a recursion function (for addition of 'n' numbers), but getting error: Below is my code and error:
def add(*n):
if len(n) == 1:
return n[0]
else:
sum = n[len(n)-1] + add(n[:-1])
return sum
a = add(2,4,6)
print(a)
Error:
Traceback (most recent call last):
File "/tmp/sessions/9d1de49c52e0e9b9/main.py", line 22, in <module>
a = add(2,4,6)
File "/tmp/sessions/9d1de49c52e0e9b9/main.py", line 18, in add
sum = n[len(n)-1] + add(n[:-1])
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
please explain what i am doing wrong
I would propose a simpler setup:
def add(*n):
if len(n) == 1:
return n[0]
return n[0] + add(*n[1:]) # n[1:] gives the "rest" of a list, i.e. all elements after the first.
In a function definition (def add(*n):), the star collects multiple separate arguments into a list.
e.g. when you call add(2, 4, 6), then n will be a list [2, 4, 6]
In a function call (add(*n)) the star spreads a list into multiple separate arguments.
e.g. when you have n = [2, 4, 6], then calling add(*n) will be as if you had called add(2, 4, 6)
In order to a list that to a function that collects its arguments, you need to spread it out first.
Your code did the first thing, but not the second. That's why it doesn't work:
def add(*n): # <-- collecting multiple arguments into a list
if len(n) == 1:
return n[0]
else:
sum = n[len(n)-1] + add(n[:-1]) # <-- not spreading list into multiple arguments
return sum
FWIW, an even shorter implementation would go like this
def add(*n):
return 0 if not n else n[0] + add(*n[1:])
n[:-1] is returning a tuple, to get the last value into add use add(n[-1])
Edit:
working solution:
def add(*n):
if len(n) == 1:
return n[0]
else:
return n[-1] + add(*n[:-1])

Merge sort in Python - `int` object is not iterable

Here is merge sort implementation in Python. I am getting the error int object is not iterable when merge_arrays() function is called. Any suggestions will be highly appreciated.
arr = [1,5,4,7,6,8,3,2,9]
def merge_arrays(_arr_left, _arr_right):
sorted_arr = []
left, right = 0, 0
for i in range(0, len(arr)):
if (_arr_left[left] < _arr_right[right]):
sorted_arr.extend(_arr_left[left])
left += 1
else:
print _arr_right[right], right
sorted_arr.extend(_arr_right[right])
right += 1
return sorted_arr
def merge_sort(_arr):
if (len(_arr) <= 1):
return _arr
_arr_left = merge_sort(_arr[:len(_arr)/2])
_arr_right = merge_sort(_arr[(len(_arr)/2):])
return merge_arrays(_arr_left, _arr_right)
try:
merge = merge_sort(arr)
print merge
except Exception as e:
print e
That particular error is coming from the fact that you're saying sorted_array.extend(_arr_left[left]). You're asking for sorted_array to have appended to it every element of the "iterable" _arr_left[left]. But _arr_left[left] isn't really iterable, it's just whatever int is at index left in _arr_left.
If you don't try then except and print the Exception, you'll see a full stack trace that will tell you which line is bad.
File "merge.py", line 27, in <module>
merge = merge_sort(arr)
File "merge.py", line 22, in merge_sort
_arr_left = merge_sort(_arr[:len(_arr)/2])
File "merge.py", line 22, in merge_sort
_arr_left = merge_sort(_arr[:len(_arr)/2])
File "merge.py", line 25, in merge_sort
return merge_arrays(_arr_left, _arr_right)
File "merge.py", line 9, in merge_arrays
sorted_arr.extend(_arr_left[left])
TypeError: 'int' object is not iterable
So you can see the problem starts at line 9. You can also insert import pdb; pdb.set_trace() before you think the Exception comes up to run the python debugger and step through your program's progression to see where the Exception appears.
As other answers have mentioned, you need to change extent to append. However, as you said in comments, you are getting list index out of range error because you are iterating over the size of arr which is 9 but subarrays have much lesser length. Try changing your merging two arrays code to the following.
while (len(_arr_left) > left) or (len(_arr_right) > right):
if (len(_arr_left) > left) and (len(_arr_right) > right):
if (_arr_left[left] < _arr_right[right]):
sorted_arr.append(_arr_left[left])
left += 1
else:
sorted_arr.append(_arr_right[right])
right += 1
elif (len(_arr_left) > left):
sorted_arr.append(_arr_left[left])
left += 1
else:
sorted_arr.append(_arr_right[right])
right += 1
As you can see in the above code, we have to test for various conditions. If both subarrays contains elements, then we compare them to each other and append to sorted_arr depending on the value evaluation. If not then we append values from individual sub-arrays. It would have been easier if instead of using left and right, you were using pop so you wouldn;t have to keep tracking of left and right
Finally, here is the working version of your code. You also need to modify
return merge_sort(...) to sorted_arr = merge_sort(...) return sorted_arr so it doesn't print everytime it returns sorted_arr
In your line 9:
sorted_arr.extend(_arr_left[left])
sorted_arr is a list
_arr_left is a list
left is an int
So, the problem is:
>>> a = [1,2,3,4]
>>> a.extend(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>>
Solution:
You can use list.append() instead of extend().
>>> a = [1,2,3,4]
>>> a.append(5)
>>> a
[1, 2, 3, 4, 5]
>>>
PS: You might have other issues with your code.

How to add elements of a list in Python 3.5.5?

My assignment is:
Write a function sumOfPairs that has one parameter of type list. The
list can be empty or contain integers. The length of the list must be
0 or an even number. If the length of the list is not 0 and is not
even, the function should print an error message and return None. You
can assume the list contains only integers. The function returns the
list of the sum of each consecutive pair of the numbers in the list.
Example: If the list is [1,5,2,10,15,2,9,3], the function returns
[6,12,17,12].
My attempt so far is:
def sumOfPairs (list1: list):
if len(list1) != 0 and len(list1)%2 != 0:
print ("Error")
return (None)
else:
x = list1.index(int)
answer = []
while x<=len(list1):
newListValue=list1(x)+list1(x+1)
answer.insert(x,newListValue)
x=x+2
return (answer)
print (sumOfPairs ([1,5,2,10,15,2,9,3]))
Yet it yields the following error upon execution:
Traceback (most recent call last):
File "C:\Users\Andrew\Desktop\lab3.py", line 79, in <module>
print (sumOfPairs ([1,5,2,10,15,2,9,3]))
File "C:\Users\Andrew\Desktop\lab3.py", line 71, in sumOfPairs
x = list1.index(int)
ValueError: <class 'int'> is not in list
How can I fix this?
def sum_of_pairs(l):
if len(l) % 2: # if the length of the list mod 2 has a remainder, the list length is uneven
print("Error, uneven length list")
else: # else, step through the list in pairs and add each pairing
return [l[i]+ l[i+1] for i in range(0,len(l),2)]
In [3]: (sum_of_pairs([1,5,2,10,15,2,9,3]))
Out[3]: [6, 12, 17, 12]
A python function that does not specify a return value as in the if len(l) % 2: will return None by default so we do not need to explicitly return None.
In [11]: l = [1,5,2,10,15,2,9,3]
In [12]: [sum(pair) for pair in zip(l[0::2],l[1::2])]
Out[12]: [6, 12, 17, 12]
I don't particularly like your approach here, but let's take a look at the error specifically.
Traceback (most recent call last):
File "C:\Users\Andrew\Desktop\lab3.py", line 79, in <module>
print (sumOfPairs ([1,5,2,10,15,2,9,3]))
File "C:\Users\Andrew\Desktop\lab3.py", line 71, in sumOfPairs
x = list1.index(int)
ValueError: <class 'int'> is not in list
Now look at the line it occurs on, and try to say it in English
x equals the first index in list1 where the value is 'int'
Note that it's not the value is AN int! This is crucial, and is the reason for the error. Your list does not INCLUDE the class int. That would be something like:
[1,2,3,int,5,6,7,8] # not your list
Much easier would be to test that ALL your indices contain ints, then just iterate through the list. Let's try that (even though your exercise says otherwise, partially to keep you from just copy/pasting this!! :D)
def sum_of_pairs(lst: list):
if len(lst) == 0 or len(lst) % 2 != 0:
raise ValueError("Invalid list length")
# makes more sense to raise an exception here than print an error
if any(not isinstance(int, el) for el in lst):
# if any element is not an int:
raise ValueError("Invalid list contents")
result_list = []
for element in lst:
first_el = element
second_el = next(lst)
# advance the iterator once to grab the next element
result_list.append(first_el + second_el) # add them and append
return result_list
Or even easier if you know how to use the grouper recipe, which is in the pydocs for the itertools module here:
def grouper(iterable, n):
return zip(*iter([iterable])*n)
def sum_of_pairs(lst: list):
# validate here, I'm not going to re-write it
return [sum(pair) for pair in grouper(lst, 2)]

Python encoding key, minus one character if too long

Here is my code so far:
def code_block(text, key):
itext = int(text)
rkey = int(key)
res= itext + rkey
def last():
return res[-1:]
if res>=11111111:
last()
return res
Here is the task I've been set:
Now we need a function to take a block of code and a key as input, where both are assumed to be 8 digits long, and encrypts each digit of the number with the corresponding digit of the key:
>>> code_block('12341234','12121212')
'24462446'
>>> code_block('66554433','44556677')
'00000000'
Where am I going wrong? Could you point me in the right direction and indicate me how I was wrong?
You are going about this the wrong way. Treat this character by character:
def code_block(text, key):
res = [str(int(c) + int(k))[-1:] for c, k in zip(text, key)]
return ''.join(res)
which gives me:
>>> code_block('12341234','12121212')
'24462446'
>>> code_block('66554433','44556677')
'00000000'
The code sums each and every character separately, turning it back into a string and only using the last character of the result; 9 + 9 is 18, but the result would be '8'.
Your code would sum the whole numbers, but that would result in:
>>> 66554433 + 44556677
111111110
which is not the correct result. Neither did you ever turn your sum back into a string again, so your code, attempting to treat the sum result as a string by slicing it, gave an exception:
>>> code_block('12341234', '12121212')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in code_block
File "<stdin>", line 6, in last
TypeError: 'int' object has no attribute '__getitem__'

Categories