Find complement of number in Python - python

I am trying to find the complement of a number in Python. I know there are other solutions but I am trying to make my own.
My first try:
def findComplement(self, num):
"""
:type num: int
:rtype: int
"""
numb = str(num)
i = 0
while(i<=len(numb)):
if numb[i] == "0":
numb[i] = "1"
else:
numb[i] = "0"
i=i+1
return int(numb)
But strings are immutable so it gave an error,
My second try:
def findComplement(self, num):
"""
:type num: int
:rtype: int
"""
numb = str(num)
numb2 = []
k =0
for j in numb:
numb2[k] = j #error on this line
k=k+1
i = 0
while(i<=len(numb2)):
if numb2[i] == "0":
numb2[i] = "1"
else:
numb2[i] = "0"
i=i+1
return int(numb2)
Error in program 2:
Line 11: IndexError: list assignment index out of range

Since other answers cover your main problem, you can also just use a dictionary for mapping 1 to 0, and vice versa:
>>> d = {'0': '1', '1': '0'}
>>> s = '0101'
>>> ''.join(d[x] for x in s)
'1010'

So I wanted find the binary complement of a number myself
but was unstatisfied with how the mask is generated and other things, cause they involved using the string representation of the binray number.
So I dug a little deeper and came across this reddit post
where they generated the mask via bitwise shifts.
And I also found out that you can get the bit count of an integer
with int.bit_lenght(<your_number>),
instead of using len(bin(<your-number>)[2:]).
Only problem is: that it returns 0 for the number 0.
So you have to account for that.
Tho I have no clue what method is more performant
and whether it is worth it compared to string manipulation.
But in the end that was my final solution
that I found was pretty neat cause it doesn't involve strings.
def bin_complement(num, on_two=False, bit_count=0):
"""
num(int) dezimal number
on_two(bool) complement on 2 else on 1
bit_count = number of bits for the mask, defaults to bits in num
returns(int) complementary number
"""
bit_count = max(bit_count, num.bit_length(), 1)
mask = 2 ** bit_count - 1
complement = num ^ mask
if on_two:
complement += 1
return complement
Edit: 2**bit_count - 1 is a faster way for doing
for _ in range(bit_count):
mask <<= 1
mask |= 1
Edit2: If you want to take the complement of fixed length bit number.
E.G: C_1(0001) -> 0001 xor 1111 = 1110
and not just 0000.
You can now set a bit_count value for the mask
so the complement works correct.

You have a few problems.
First you are not converting your input to a binary string properly. This can be done by numb = bin(num)[2:] instead of num = str(num).
Second, you are trying to index into your empty numb2 list. Actually there is no need to create a separate numb2 list, you can just operate directly on your numb string, as in your first attempt. For example:
for i in range(len(numb)):
if numb[i] == "0":
numb[i] = "1"
else:
numb[i] = "0"
Finally, to convert your binary string back to an int you should do int(numb, 2) not int(numb).

numb2 is an empty list. It does not have any elements to be addressed (and updated). What you need is a bytearray, rather than a list (or a string):
def findComplement(self, num):
"""
:type num: int
:rtype: int
"""
numb = bytearray(str(num), 'utf-8')
i = 0
while(i<len(numb)):
if numb[i] == ord("0"):
numb[i] = ord("1")
else:
numb[i] = ord("0")
i=i+1
return int(numb)
As can be seen, this requires some minor other changes, as the stored data in a bytearray is a byte (0-255) rather than a char. The solution is to use the ord function, to get the byte number from "0" and "1". In addition there is a small issue (off by one) in your whileexpression. Since the indexing and your count start at zero i should be strictly smaller than the length of the string.
I would also like to add that there are simper ways to achive the complement of 0 and/or 1, though.

Let's say we have to find complement of 101 if we xor the input with the mask 111 then we will get 010 which is complement.
def findComplement(self, num: int) -> int:
mask_len=len(bin(num))-2
mask=int("1"*mask_len,2)
return mask^num

For those looking for a one-liner, here is one:
int(bin(value)[2:].zfill(numbits).translate(str.maketrans('01', '10')), 2)
The above computes a numbits-bit ones' complement for value.
Since str.maketrans('01', '10') is a constant (dictionary), one can compute it ahead of time:
dMatrix = str.maketrans('01', '10') # which is {48: 49, 49: 48}
int(bin(value)[2:].zfill(numbits).translate(dMatrix), 2)
Converting this one-liner to a function is straightforward:
def onescomplement(value, numbits):
return int(bin(value)[2:].zfill(numbits).translate(str.maketrans('01', '10')), 2)
HTH

Don't you just mean the ~ operator, e.g:
def findComplement(self, num):
return ~num

Related

IQ test function in Python not working as intended

I'm having trouble with this code below.
My task is to create a function, that among the given numbers finds one that is different in evenness, and returns a position of that number. The numbers are given as a string. So far I have managed to convert the string into an integer list, then using for loop to iterate through each number.
The problem I'm encountering is that I've managed to return only the position of an odd number among the even numbers, and I can't continue on with the code for vice versa action, because it only returns the position of the odd number.
Here is the code:
def iq_test(numbers):
# Splitting the "numbers" string
num_split = numbers.split()
# converting the splitted strings into int
num_map = map(int, num_split)
# converting the object into list
list_num = list(num_map)
for n in list_num:
if not n%2 == 0:
return list_num.index(n) + 1
Your problem is, that you are assuming, that you are searching for the first even number. What you have to do, is to first decide, what you are searching for. You could for example simply first count the number of even numbers. If it is one, then you are looking for an even number, otherwise, you are looking for an odd. As you don't care for the actual numbers, I would map all of them to their value mod 2 as so:
num_map = list(map(lambda x: int(x) % 2, num_split))
Then, the rest is simple. For example like this:
def iq_test(numbers):
# Splitting the "numbers" string
num_split = numbers.split()
# converting the splitted strings into even (0) or odd (1)
num_map = list(map(lambda x: int(x) % 2, num_split))
# return the correct position based on if even or odd is in search
evens = num_map.count(0)
if evens == 1:
return num_map.index(0) + 1
else:
return num_map.index(1) + 1
I came up with a similar and a little bit shorter solution
def iq_test(numbers):
# first check what im looking for "even" or "odd", map a lambda function that basically does it for me, using the numbers argument as a list type and afterwards cast it into a list so i can iterate later on
num_map = list(map(lambda x: 'e' if int(x) % 2 == 0 else 'o', numbers.split()))
# search for even numbers numbers
if num_map.count('e') == 1:
return num_map.index('e') + 1
# search for odd numbers numbers
return num_map.index('o') + 1
def iq_test(numbers):
# Splitting the "numbers" string
num_split = numbers.split()
# converting the splitted strings into int
num_map = map(int, num_split)
# converting the object into list
list_num = list(num_map)
for n in list_num:
if not n%2 == 0:
return list_num.index(n) + 1

Python- Expanded form of a number raised to the power of ten

I'm pretty new to coding and I am trying to write a python script where a user enters an integer and it displays that integer in expanded form raised to the power of 10's.
Example: A user enters 643541 and the script outputs 643541 = (6x10^5 )+(4x10^4)+(3x10^3)+(5x10^2)+(4x10^1)+(1x10^0)
This is my code
A = [7000, 400, 70,1]
cond = True
y = 0
i = 0
sizeArray = len(A)
for i in range(0, sizeArray-1):
while cond == True:
if A[i]%10 == 0:
A[i] = A[i]/10
y += 1
else:
cond = False
print(y)
I tried working with a sample array to test the number of zero's but I don't know how i will be able to output the result as above.
How can I accomplish this?
You can transform your input integer 643541 to an array of digits [6,4,3,5,4,1]. Then maintain a variable for the exponent. It will be decremented for each digit in the array
def function(num):
digits = str(num) # convert number to string
output = []
for i, digit in enumerate(digits):
output.append("(" + digit + "x10^" + str(len(digits)-i-1) + ")")
return " + ".join(output)
Here len(digits)-i-1 plays the role of the variable that maintains exponent value
Every question like this deserves a solution using a list comprehension:
>>> n = 123456
>>> '+'.join([ '({1}x10^{0})'.format(*t) for t in enumerate(str(n)[::-1]) ][::-1])
'(1x10^5)+(2x10^4)+(3x10^3)+(4x10^2)+(5x10^1)+(6x10^0)'
Explanation:
str(n)[::-1] converts the number to a string and then reverses the string, giving the digits of the number, as strings, from least-significant to most-significant.
enumerate returns pairs t = (i, d) where i is the index and d is the digit. Since the sequence is from least-significant to most-significant, the index equals the corresponding exponent of 10.
*t unpacks (i, d) for {0} and {1} in the format string, so the result is like ({d}x10^{i}).
The [::-1] applied to the list comprehension reverses the results back into the right order.
'+'.join joins those results together into a single string, with the + symbol between the parts.

How do I return the number of unique digits in a positive integer

Example: unique_dig(123456) All unique
6
I'm trying to write code to have a function return how many unique numbers there are in a positive integer.
count = 0
for i in unique_digits:
if count.has_key(i):
count[i] += 1
else:
count[i] = count + 1
Convert the integer to a string, convert that string to a set of characters, then get the size of the set.
>>> N = 12334456
>>> len(set(str(N)))
6
I am indebted to Stefan Pochmann for teaching me something. (See the comments.)
Here is a solution in pseudocode. You should be able to convert this into Python without too much trouble. Depending on the limitations (I assume this is homework of some kind), you may need to nest a second loop to check each char against the arrayOfUniqueCharacters.
someInputString = "abracadabra"
emptyArrayOfUniqueCharacters = []
FOR char IN someInputString
IF char NOT IN arrayOfUniqueChars
APPEND char TO arrayOfUniqueChars
RETURN length OF arrayOfUniqueChars

Convert signed binary number into integer in Python

I found out that in python, if you use bin:
>>> bin(4)
'0b100'
>>> bin(-4)
'-0b100'
but if you try this:
-4 >> 8 => -1
in fact, when right shift more than 3 bits, the answer is always -1. I know this is implementation stuff, but I came across this problem:
In the following array, find out the number which appears only once, while others appears always three times
[-2,-2,1,1,-3,1,-3,-3,-4,-2]
This is the code
class Solution(object):
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if nums == None:
return None
ans = 0
for i in range(32):
numOfI = 0
for num in nums:
if (( num >> i) & 1) == 1 :
numOfI += 1
numOfI %=3
print i,numOfI
if numOfI != 0:
ans = ans + (numOfI << i)
return ans
the answer should be -4, but instead I get 11111111111111111111111111111100; how can I convert it into -4?
Bit manipulation on Python are easily done with int.from_bytes and int.to_bytes.
On the other hand, solving the "find the value appearing x times" is easily solved using the Counter class:
>>> from collections import Counter
>>> values = [-2,-2,1,1,-3,1,-3,-3,-4,-2]
>>> [value for value, count in Counter(values).items() if count == 1]
[-4]
Using from_bytes and to_bytes is clear and readable, so you don't want to try to do the conversion yourself.
Using Counter is also more readable than your cryptic implementation, yet my one-liner may not be the most readable imaginable version, it's still a single line and far more readeable.

How to convert str in a list to int without using int() in Python

The question is pretty straightforward. Sorry I am very new to this. I'm not allowed to use int().
The algorithm you are looking for is:
initialise number to 0
for each character in str
multiply number by 10
find number of character (ascii value, avaiable from ord(), - 48 is simplest)
add character number to number
Of course, you should check that the string is actually all numbers first.
Here is how to do it for binary (base2) numbers:
>>> bin(12)
'0b1100'
>>> sum([2**i * (ord(ch)-ord('0')) for i, ch in enumerate(reversed('1100'))])
12
Here is a nice, Pythonic way of doing it.
def str_to_int(s):
if type(s) != str:
raise TypeError("invalid type for str_to_int: {}".format(type(s)))
if not s.isdigit():
raise ValueError("invalid literal for str_to_int: '{}'".format(s))
return sum((ord(char) - 48) * 10**(len(s) - n) for n, char in enumerate(s, start=1))
If you don't care about checking the argument to make sure it's a string and contains only digits, then it can be reduced down to the following one-liner:
str_to_int = lambda s: sum((ord(char) - 48) * 10**(len(s) - n) for n, char in enumerate(s, start=1))
This answer depends on the numbers' ASCII values being in sequential order. You want to simply reverse the string, then turn each digit to an int and add it's weighted value to the string. So, if your number is "12345", your first addend would be 5*1, or 5. Your second would be 4*10 or 40. Keep adding them and multiplying your weight by 10 until you reach the end of the string, and you are done!
def str_to_int(string):
if not string.isdigit():
raise ValueError("String must be a digit")
weight = 1
ans = 0
for c in reversed(string):
i = ord(c) - ord('0')
ans = ans + i*weight
weight = weight * 10
return ans
If you can do it for one string, you can do it for all strings! Either use a for loop or the handy map function:
l = ["12312" , '32355']
print(list(map(str_to_int, l)))
print([str_to_int(i) for i in l])

Categories