Narcissistic numbers in Python - python

I am beginner to the Python programming language and I have been using a website to help me exercise. It gave me this challenge to make a program that returns true if a given number is narcissistic or false otherwise.
Examples of narcissistic numbers:
153 (3 digits): 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153
1634 (4 digits): 1^4 + 6^4 + 3^4 + 4^4 = 1 + 1296 + 81 + 256 = 1634
But for some reason when the number 371 is given the function returns False instead of True.
The code:
def narcissistic(value):
logical = True
logical2 = True
i = 0
j = 0
notation = 10
sum = 0
#Calculating the number notation
while logical:
if 10 ** i <= value:
notation = 10 ** i
i = i + 1
else:
logical = False
#i from now on is also the qauntity of digits
while logical2:
if ( notation / 10 ** j ) >= 1:
sum = sum + ( value // ( notation / 10 ** j ) ) ** i
j = j + 1
else:
logical2 = False
if sum == value:
return True
else:
return False

Your code is very close! The issue lies here:
sum = sum + ( value // ( notation / 10 ** j ) ) ** i
For 1634, this multiplies 1, 16, 163, and 1634. You need only the LSB of these numbers, in this example 1, 6, 3, and 4 - use the modulo operator to get this. If we mod them by 10 to get only the LSB...
sum = sum + (( value // ( notation / 10 ** j ) ) % 10) ** i
...then the code works perfectly.
Demo

It would probably be easier to do this task by converting the value to a string and back. Taking the length of the string is an easy way to get the number of digits ("the poor man's logarithm"), and you can easily iterate over individual digits:
def narcissistic(value):
str_value = str(value)
num_digits = len(str_value)
return (value == sum(int(digit) ** num_digits for digit in str_value))
>>> narcissistic(153)
True
>>> narcissistic(1634)
True
>>> narcissistic(371)
True
>>> narcissistic(372)
False

Could grab individual digits without converting to string
import math
def narcissistic(value):
n = math.floor(math.log10(value)) + 1
x = [math.floor((value/10**i)%10)**n for i in range(n)]
print(sum(x) == value)
narcissistic(371)
#True

change ^ to **
def narcissistic(number):
number_string = str(number)
number_len = len(number_string)
number_nar = 0
for char in number_string:
number_nar+= int(char) ** number_len
return number_nar
number = 153
number_nar = narcissistic(number)
print(number_nar)
number = 1634
number_nar = narcissistic(number)
print(number_nar)
output:
153
1634

This can be solved using list comprehension in 1 line of code.
def Narcissistic(x):
y = sum([int(i)**(len(x)) for i in (x)])
return Narcissistic(x)

Related

Find missing arrithmetic operations in arithmetic expression

I was given the following task:
Richard likes to ask his classmates questions like the following:
4 x 4 x 3 = 13
In order to solve this task, his classmates have to fill in the missing arithemtic operators (+, -, *, /) that the created equation is true. For this example the correct solution would be 4 * 4 - 3. Write a piece of code that creates similar questions to the one above. It should comply the following rules:
The riddles should only have one solution (e.g. not 3 x 4 x 3 = 15, which has two solutions)
The operands are numbers between 1-9
The solution is a positive integer
Point before dashes is taken into account (e.g. 1 + 3 * 4 = 13)
Every interim result is an integer (e.g. not 3 / 2 * 4 = 6)
Create riddles up to 15 arithmetic operands, which follow these rules.
My progress so far:
import random
import time
import sys
add = lambda a, b: a + b
sub = lambda a, b: a - b
mul = lambda a, b: a * b
div = lambda a, b: a / b if a % b == 0 else 0 / 0
operations = [(add, '+'),
(sub, '-'),
(mul, '*'),
(div, '/')]
operations_mul = [(mul, '*'),
(add, '+'),
(sub, '-'),
(div, '/')]
res = []
def ReprStack(stack):
reps = [str(item) if type(item) is int else item[1] for item in stack]
return ''.join(reps)
def Solve(target, numbers):
counter = 0
def Recurse(stack, nums):
global res
nonlocal counter
valid = True
end = False
for n in range(len(nums)):
stack.append(nums[n])
remaining = nums[:n] + nums[n + 1:]
pos = [position for position, char in enumerate(stack) if char == operations[3]]
for j in pos:
if stack[j - 1] % stack[j + 1] != 0:
valid = False
if valid:
if len(remaining) == 0:
# Überprüfung, ob Stack == target
solution_string = str(ReprStack(stack))
if eval(solution_string) == target:
if not check_float_division(solution_string)[0]:
counter += 1
res.append(solution_string)
if counter > 1:
res = []
values(number_ops)
target_new, numbers_list_new = values(number_ops)
Solve(target_new, numbers_list_new)
else:
for op in operations_mul:
stack.append(op)
stack = Recurse(stack, remaining)
stack = stack[:-1]
else:
if len(pos) * 2 + 1 == len(stack):
end = True
if counter == 1 and end:
print(print_solution(target))
sys.exit()
stack = stack[:-1]
return stack
Recurse([], numbers)
def simplify_multiplication(solution_string):
for i in range(len(solution_string)):
pos_mul = [position for position, char in enumerate(solution_string) if char == '*']
if solution_string[i] == '*' and len(pos_mul) > 0:
ersatz = int(solution_string[i - 1]) * int(solution_string[i + 1])
solution_string_new = solution_string[:i - 1] + solution_string[i + 1:]
solution_string_new_list = list(solution_string_new)
solution_string_new_list[i - 1] = str(ersatz)
solution_string = ''.join(str(x) for x in solution_string_new_list)
else:
return solution_string
return solution_string
def check_float_division(solution_string):
pos_div = []
solution_string = simplify_multiplication(solution_string)
if len(solution_string) > 0:
for i in range(len(solution_string)):
pos_div = [position for position, char in enumerate(solution_string) if char == '/']
if len(pos_div) == 0:
return False, pos_div
for j in pos_div:
if int(solution_string[j - 1]) % int(solution_string[j + 1]) != 0:
# Float division
return True, pos_div
else:
# No float division
return False, pos_div
def new_equation(number_ops):
equation = []
operators = ['+', '-', '*', '/']
ops = ""
if number_ops > 1:
for i in range(number_ops):
ops = ''.join(random.choices(operators, weights=(4, 4, 4, 4), k=1))
const = random.randint(1, 9)
equation.append(const)
equation.append(ops)
del equation[-1]
pos = check_float_division(equation)[1]
if check_float_division(equation):
if len(pos) == 0:
return equation
for i in pos:
equation[i] = ops
else:
'''for i in pos:
if equation[i+1] < equation[i-1]:
while equation[i-1] % equation[i+1] != 0:
equation[i+1] += 1'''
new_equation(number_ops)
else:
print("No solution with only one operand")
sys.exit()
return equation
def values(number_ops):
target = 0
equation = ''
while target < 1:
equation = ''.join(str(e) for e in new_equation(number_ops))
target = eval(equation)
numbers_list = list(
map(int, equation.replace('+', ' ').replace('-', ' ').replace('*', ' ').replace('/', ' ').split()))
return target, numbers_list
def print_solution(target):
equation_encrypted_sol = ''.join(res).replace('+', '○').replace('-', '○').replace('*', '○').replace('/', '○')
print("Try to find the correct operators " + str(equation_encrypted_sol) + " die Zahl " + str(
target))
end_time = time.time()
print("Duration: ", end_time - start_time)
input(
"Press random button and after that "ENTER" in order to generate result")
print(''.join(res))
if __name__ == '__main__':
number_ops = int(input("Number of arithmetic operators: "))
# number_ops = 10
target, numbers_list = values(number_ops)
# target = 590
# numbers_list = [9, 3, 5, 3, 5, 2, 6, 3, 4, 7]
start_time = time.time()
Solve(target, numbers_list)
Basically it's all about the "Solve(target, numbers)" method, which returns the correct solution. It uses Brute-Force in order to find that solution. It receives an equation and the corresponding result as an input, which has been generated in the "new_equation(number_ops)" method before. This part is working fine and not a big deal. My main issue is the "Solve(target, numbers)" method, which finds the correct solution using a stack. My aim is to make that program as fast as possible. Currently it takes about two hours until an arithmetic task with 15 operators has been found, which follows the rules above. Is there any way to make it faster or maybe another approach to the problem besides Brute-Force? I would really appreciate your help :)
This is mostly brute force but it only takes a few seconds for a 15 operation formula.
In order to check the result, I first made a solve function (recursive iterator) that will produce the solutions:
def multiplyDivide(numbers):
if len(numbers) == 1: # only one number, output it directly
yield numbers[0],numbers
return
product,n,*numbers = numbers
if product % n == 0: # can use division.
for value,ops in multiplyDivide([product//n]+numbers):
yield value, [product,"/",n] + ops[1:]
for value,ops in multiplyDivide([product*n]+numbers):
yield value, [product,"*",n] + ops[1:]
def solve(target,numbers,canGroup=True):
*others,last = numbers
if not others: # only one number
if last == target: # output it if it matches target
yield [last]
return
yield from ( sol + ["+",last] for sol in solve(target-last,others)) # additions
yield from ( sol + ["-",last] for sol in solve(target+last,others)) # subtractions
if not canGroup: return
for size in range(2,len(numbers)+1):
for value,ops in multiplyDivide(numbers[-size:]): # multiplicative groups
for sol in solve(target,numbers[:-size]+[value],canGroup=False):
yield sol[:-1] + ops # combined multipicative with rest
The solve function recurses through the numbers building an addition or subtraction with the last number and recursing to solve a smaller problem with the adjusted target and one less number.
In addition to the additions and subtraction, the solve function groups the numbers (from the end) into consecutive multiplications/divisions and processes them (recursing into solve) using the resulting value that will have calculation precedence over additions/subtractions.
The multiplyDivide function (also a recursive generator) combines the group of numbers it is given with multiplications and divisions performed from left to right. Divisions are only added when the current product divided by the additional number produces an integer intermediate result.
Using the solve iterator, we can find a first solution and know if there are more by iterating one additional time:
def findOper(S):
expression,target = S.split("=")
target = int(target.strip())
numbers = [ int(n.strip()) for n in expression.split("x") ]
iSolve = solve(target,numbers)
solution = next(iSolve,["no solution"])
more = " and more" * bool(next(iSolve,False))
return " ".join(map(str,solution+ ["=",target])) + more
Output:
print(findOper("10 x 5 = 2"))
# 10 / 5 = 2
print(findOper("10 x 5 x 3 = 6"))
# 10 / 5 * 3 = 6
print(findOper("4 x 4 x 3 = 13"))
# 4 * 4 - 3 = 13
print(findOper("1 x 3 x 4 = 13"))
# 1 + 3 * 4 = 13
print(findOper("3 x 3 x 4 x 4 = 25"))
# 3 * 3 + 4 * 4 = 25
print(findOper("2 x 6 x 2 x 4 x 4 = 40"))
# 2 * 6 * 2 + 4 * 4 = 40 and more
print(findOper("7 x 6 x 2 x 4 = 10"))
# 7 + 6 * 2 / 4 = 10
print(findOper("2 x 2 x 3 x 4 x 5 x 6 x 3 = 129"))
# 2 * 2 * 3 + 4 * 5 * 6 - 3 = 129
print(findOper("1 x 2 x 3 x 4 x 5 x 6 = 44"))
# 1 * 2 + 3 * 4 + 5 * 6 = 44
print(findOper("1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 8 x 7 x 6 x 5 x 4 x 1= 1001"))
# 1 - 2 - 3 + 4 * 5 * 6 * 7 / 8 * 9 + 8 * 7 - 6 + 5 + 4 + 1 = 1001 and more
print(findOper("1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 8 x 7 x 6 x 5 x 4 x 1= 90101"))
# no solution = 90101 (15 seconds, worst case is not finding any solution)
In order to create a single solution riddle, the solve function can be converted to a result generator (genResult) that will produce all possible computation results. This will allow us to find a result that only has one combination of operations for a given list of random numbers. Given that the multiplication of all numbers is very likely to be a unique result, this will converge rapidly without having to go through too many random lists:
import random
def genResult(numbers,canGroup=True):
*others,last = numbers
if not others:
yield last
return
for result in genResult(others):
yield result - last
yield result + last
if not canGroup: return
for size in range(2,len(numbers)+1):
for value,_ in multiplyDivide(numbers[-size:]):
yield from genResult(numbers[:-size]+[value],canGroup=False)
def makeRiddle(size=5):
singleSol = []
while not singleSol:
counts = dict()
numbers = [random.randint(1,9) for _ in range(size)]
for final in genResult(numbers):
if final < 0 : continue
counts[final] = counts.get(final,0) + 1
singleSol = [n for n,c in counts.items() if c==1]
return " x ".join(map(str,numbers)) + " = " + str(random.choice(singleSol))
The reason we have to loop for singleSol (single solution results) is that there are some cases where even the product of all numbers is not a unique solution. For example: 1 x 2 x 3 = 6 could be the product 1 * 2 * 3 = 6 but could also be the sum 1 + 2 + 3 = 6. There aren't too many of those cases but it's still a possibility, hence the loop. In a test generating 1000 riddles with 5 operators, this occurred 4 times (e.g. 4 x 1 x 1 x 4 x 2 has no unique solution). As you increase the size of the riddle, the occurrence of these no-unique-solution patterns becomes more frequent (e.g. 6 times generating 20 riddles with 15 operators).
output:
S = makeRiddle(15) # 7 seconds
print(S)
# 1 x 5 x 2 x 5 x 8 x 2 x 3 x 4 x 1 x 2 x 8 x 9 x 7 x 3 x 2 = 9715
print(findOper(S)) # confirms that there is only one solution
# 1 * 5 * 2 * 5 * 8 * 2 * 3 * 4 - 1 + 2 + 8 * 9 + 7 * 3 * 2 = 9715

Adding numbers in python and in line using function recursion

Hey guys I have a code like this
def add_sum(n):
numStr = str(n)
sum = 0
for i in range(len(num_str)):
sum += int(numStr[])
return sum
print(add_sum(546))
I want the answer to be this way.
output: 5 + 4 + 6 = 15
How can I make this work for me?
add_sum = lambda number: sum([int(x) for x in str(number)])
If you wanna do it the string conversion way
Edit: I assume you were referring to the loop, when you mentioned "recursion"?
If you want to loop over digits of a number, you can also use module 10 and divide the number each time.
A solution with recursion that does not convert int to str (which is kind of an expensive operation):
def add_sum(n):
return 0 if n == 0 else n % 10 + add_sum(n // 10)
If you prefer a solution without recursion:
def add_sum(n):
result = 0
while n != 0:
result += n % 10
n //= 10
return result
If you want to convert int to str:
def add_sum(n):
return sum(map(int, str(n)))
You can try this non-recursive code.
def add_sum(n):
temp = list(str(n))
ans = 0
for i in temp:
ans += int(i)
print(f"{' + '.join(temp)} = {ans}")
for i in range(3):
num = int(input())
add_sum(num)
Output:
546
5 + 4 + 6 = 15
258
2 + 5 + 8 = 15
6985
6 + 9 + 8 + 5 = 28
You can try this
def add_sum(n):
numStr = str(n)
sum1 = 0
for i in range(len(numStr)):
sum1 += int(numStr[i])
return ' + '.join([str(x) for x in n]),sum1
i,j=add_sum('546')
print(i,'=',j)
This also works
def add(num):
num_ = str(num)
if (len(num_) == 1):
return int(num)
else:
x = add(num_[1:])
return (x + int(num_[0]))
def add_sum(n):
numStr = str(n)
sum = 0
for i in range(len(numStr)):
sum += int(numStr[i])
return sum
print(add_sum(546))
This is the correct version of your code!
You can use your function With recursion like this!
def add_sum(n, sum=0):
if n == 0:
return sum
else:
sum += n % 10
return add_sum(int(n/10), sum)
print(add_sum(546))
here you go! sol. with recursion
def add_sum(n, sum=0, orignal=0):
if n == 0:
return(f"{orignal} => {' + '.join(str(orignal))} = {sum}")
elif orignal == 0:
orignal = n
sum += n % 10
else:
sum += n % 10
return add_sum(int(n/10), sum, orignal)
print(add_sum(54236))
Output:
54236 => 5 + 4 + 2 + 3 + 6 = 20

Python function to check if credit card number is a valid number using for loops

So this is a cs assignment, and I wrote code that works for 2 out of the 9 test cases (which are unknown), but I don't know why it won't work/pass any other ones. I understand I should try to figure out how to do this on my own, and I have tried, but I am really lost and need help!
"Write a file named credit_card.py containing a single function, check. Check accepts a single input – a positive integer. It returns True if the integer represents a valid credit card number. As with all functions that return a bool value, if it does not return True it should return False.
Credit card numbers have what is called a check digit. This is a simple way of detecting common mis-typings of card numbers. The algorithm is as follows:
Form a sum of every other digit, including the right-most digit; so 5490123456789128 (5490123456789128) sums to 4 + 0 + 2 + 4 + 6 + 8 + 1 + 8 = 33.
Double each remaining digit, then sum all the digits that creates it; the remaining digits (5 9 1 3 5 7 9 2) in our example (5490123456789128) double to 10 18 2 6 10 14 18 4, which sums to 1+0 + 1+8 + 2 + 6 + 1+0 + 1+4 + 1+8 + 4 = 37
Add the two sums above (33 + 37 = 70)
If the result is a multiple of 10 (i.e., its last digit is 0) then it was a valid credit card number."
def check(x):
num1 = 0
num2 = 0
if x < 0:
return False
for i in str(x) [1::2]:
num1 += int(i)
return num1
for i in str(x) [0::2]:
num2 += int(int(i * 2) % 10) + int(int(i * 2) / 10)
return num2
check_digit = num1 + num2
if check_digit % 10 == 0:
return True
else:
return False
def check(x):
if x[0] == '-': # x is [str], "x < 0" is wrong
return False
try:
nums = map(int, x)
except Exception:
return False
sum1 = 0
sum2 = 0
for i in nums[1::2]:
sum1 += int(i)
for i in nums[0::2]:
sum2 += ((i * 2) % 10 + (i * 2) / 10) # i is [str], "i * 2" is wrong
check_digit = sum1 + sum2
if check_digit % 10 == 0:
return True
else:
return False

checking integer overflow in python

class Solution(object):
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
negative = False
if(x < 0):
x = x * -1
negative = True
else:
x = x
sum = 0
dig = 1
strX = str(x)
lst = list(strX)
for i in lst:
sum += int(i) * dig
dig *= 10
if(abs(sum) > 2 ** 32):
return 0
elif(negative == True):
return sum * -1
else:
return sum
This is a leetcode problem that asks us to reverse an integer. I know it's a dirty code but it still works but it does not return 0 when the reversed integer overflows. I tried to check that on the line
if(abs(sum) > 2 ** 32):
return 0
but one of the test cases gives me:
Input: 1563847412
Output: 2147483651
Expected: 0
First, I am not sure why this overflows, and I am not sure how to fix this.
Thanks!
change if(abs(sum) > 2 ** 32): to if(abs(sum) > (2 ** 31 - 1)): or abs(sum) > (1 << 31) - 1): The largest 32 bit signed interger is actually not 2^32 but (2 ^ (31)) -1). because we need one bit reserve as the sign bit.
Read about it here of why The number 2,147,483,647 (or hexadecimal 7FFF,FFFF) is the maximum positive value for a 32-bit signed binary integer
I guess some thing light weight like below could perhaps achieve the same logic, For someone else looking , the main overflow check after reversed 32 bit int is
if(abs(n) > (2 ** 31 - 1)):
return 0
Full code below
def reverse(self, x):
neg = False
if x < 0:
neg = True
x = x * -1
s = str(x)[::-1]
n = int(s)
if neg:
n = n*-1
if(abs(n) > (2 ** 31 - 1)):
return 0
return n
The largest 32-bit signed integer is (1 << 31) - 1 which is (2**31)-1 but not (2**32).
Try This way :
class Solution(object):
def reverse(self, x):
"""
:type x: int
:rtype: int
"""
negative = False
if (x < 0):
x = x * -1
negative = True
else:
x = x
sum = 0
dig = 1
strX = str(x)
lst = list(strX)
for i in lst:
sum += int(i) * dig
dig *= 10
if (abs(sum) > ((1 << 31) - 1)): #use (1 << 31) - 1) instead of 2 ** 32
return 0
elif (negative == True):
return sum * -1
else:
return sum
if __name__ == '__main__':
x = 1563847412
sol = Solution().reverse(x)
print(sol)
Output :
0
class Solution:
def reverse(self, x: int) -> int:
split = [i for i in str(x)]
split = split[::-1]
final = ''
if split[-1]=='-':
final += '-'
for i in split[0:-1]:
print(i)
final+=i
else:
for i in split[0:]:
final+=i
final = int(final)
if(abs(final) > (2 ** 31 - 1)):
return 0
return(final)
you can simply use:
if sum >= pow(2,31)-1:
return 0
if sum > ((1 << 31) - 1):
return 0
else:
if negative == True:
sum = -sum
return sum

Ceil and floor equivalent in Python 3 without Math module?

I need to ceil and floor 3/2 result (1.5) without using import math.
math.floor(3/2) => 3//2
math.ceil(3/2) => ?
OK, here is the problem:
to sum all numbers
15 + 45 + 15 + 45 + 15 ...
with N items.
sum = (n//2) * 5 + int(n/2) * 15
>>> 3/2
1.5
>>> 3//2 # floor
1
>>> -(-3//2) # ceil
2
Try
def ceil(n):
return int(-1 * n // 1 * -1)
def floor(n):
return int(n // 1)
I used int() to make the values integer. As ceiling and floor are a type of rounding, I thought integer is the appropriate type to return.
The integer division //, goes to the next whole number to the left on the number line. Therefore by using -1, I switch the direction around to get the ceiling, then use another * -1 to return to the original sign. The math is done from left to right.
I know this is old...but you can call those like this too:
>>> (3/2).__ceil__()
2
>>> (3/2).__floor__()
1
edit: this is for python 3.9 and above
Try:
def ceil(n):
res = int(n)
return res if res == n or n < 0 else res+1
def floor(n):
res = int(n)
return res if res == n or n >= 0 else res-1
try it like:
if a%b != 0:
print(int(a//b + 1))
else:
print(int(a/b))

Categories

Resources