Python - direct a functions output to a set - python-3.x

I am new to python and was going through this following code which takes in an integer and outputs the positions of 1's in its binary value.
def L(encoded_set):
print('{', end = '')
i = 0
if encoded_set:
while encoded_set % 2 == 0:
encoded_set //= 2
i += 1
print(i, end = '')
encoded_set //= 2
i += 1
while encoded_set:
if encoded_set % 2:
print(',', i,end = '')
encoded_set //= 2
i += 1
print('}')
For ex: Binary of 54 is 110110 so the code will output: {1, 2, 4, 5}
Now, i need to direct this output to a set so that i can work with the individual set elements. Something like X[0] = 1, X[1] = 2, X[2] = 4
and X[3] = 5. I'm not sure how to do this.

I would go for bit-shifting of value
ones = []
pos = 0
while val:
if val & 1:
ones.append(pos)
pos += 1
val >>= 1
Your solution numbers from first non-0 most-significant bit - which may be meaningless unless the position of MSB is known (yes, you know it, but you'll have to add extra code for that). My solution counts position relative to LSB.

As a more elegant way you can convert your number to binary with bin function and use enumerate and a list comprehension to return the proper positionsm,and return the list of indices:
>>> def pos(num) :
... return [i for i,j in enumerate(bin(num)[2:],1) if j=='1']
...
>>> pos(54)
[1, 2, 4, 5]
NOTE that the result of bin has a 0b on leading of the number so you need to loop over the slice of your binary number (bin(num)[2:]).

Related

Moving 0's in a list without interfering the order of other non-zero items

I am trying to solve a programming quiz on Leet Code. The question is:
Given an integer array nums, move all 0's to the end of it while maintaining the relative order of the non-zero elements.
Note that you must do this in-place without making a copy of the array.
 
Example 1:
Input: nums = [0,1,0,3,12]
Output: [1,3,12,0,0]
Example 2:
Input: nums = [0]
Output: [0]
 
Constraints:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
 
My solution
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
count = 0
for item in nums:
if item == 0:
nums.remove(item)
count += 1
for i in range(0,count):
nums.append(0)
What my solution is trying to do is that:
It traverses the entire list.
If any item is 0, the item is removed. The counter increments by 1.
After traversing the list, append counter number of 0's to the list.
However, my solution didn't pass the following test case.
Test input:
[0,0,1]
Expected output:
[1,0,0]
My output:
[0,1,0]
Where does my script go wrong?
You can try this in a simple way:
>>> nums = [0,1,0,3,12]
>>> output=[i for i in nums if i!=0]
>>> for cnt in range(nums.count(0)):
output.extend("0")
>>> print(output)
[1, 3, 12, '0', '0']
Same code can be convert into one liner solution as suggested by #deadshot:
[i for i in nums if i!=0] + [0] * nums.count(0)
The other answer together with the one line solution from comment are nice pythonic solutions. If you really need the same list modified in place you can do something similar with bubble-sort, swap elements until all the zeroes are at the end.
nums = [0, 1, 0, 3, 12]
done = False
while not done:
done = True
for i in range(len(nums) - 1):
if nums[i] == 0 and nums[i + 1] != 0:
nums[i] = nums[i + 1]
nums[i + 1] = 0
done = False
print(nums)
In your solution, remove removes only the first occurrence or a zero. To make it work you need to remove until there are no zeros remaining and then append the final number of zeroes at the end.

Convert a number to binary in Python

Given a non-negative integer n, write a function to_binary/ToBinary which returns that number in a binary format.
This is my code but some tests don't pass.
I appreciate it if you help me fix my code:
def to_binary(n):
string = ""
if n > 2:
string = string + str(n % 2)
x = n // 2
while x >= 2:
i = x % 2
string = string + str(i)
x = x // 2
string = string + str(1)
l = len(string)
string[l::-1]
return int(string)
else:
if n == 1:
return 1
if n == 2:
return 10
Few points to note.
Changing the concatenation logic will generate the string in reverse. You won't have to reverse it in the end.
In [10]: s = ''
In [11]: for i in range(5):
...: s = s + str(i)
...:
In [12]: s
Out[12]: '01234'
In [13]: s = ''
In [14]: for i in range(5):
...: s = str(i) + s # add the existing string after i
...:
In [15]: s
Out[15]: '43210'
You don't require a different logic for numbers less than 2. You shouldn't have to hardcode anything unless you're using recursion. In which case, hardcoding is simply the base case.
You are not reversing the string at all.
s[::-1]
This does not reverse a string in-place. Strings in python are immutable. What you can do is,
s = s[::-1]
Not providing the limits in a slice syntax is the same as providing start and end values (0 and length). You don't have to explicitly write s[len(s)::-1].
Your logic is almost correct. Just remove everything and keep the while loop and the code will work.
def to_bin(x):
if x == 0:
return '0'
b = ''
while x > 0:
b = str(x%2) + b
x //= 2
return b
There are of course several ways to do this without writing code just by using the builtin features of python.
You could try the implementing the mathematical method of converting bases into Python. Every number can be expressed as the sum of the powers of a base. For binary, base 2, this would be N*2**n + ... + A*2**3 + B*2**2 + C*2**1 + D*2**0. The hardest part is finding N, but from there we can use divmod to solve for the other variables.
def get_highest_power(num, base=2):
n = 0
while True:
if base**(n+1) >= num:
break
n += 1
return n
def solve_for_coefficients(num, power, base=2):
coefficients = []
for p in range(power, -1, -1):
coef, num = divmod(num, base**p)
coefficients.append(coef)
return coefficients
leading_power = get_highest_power(1000)
coefficients = solve_for_coefficients(1000, leading_power)
In order to get the base conversion, just use something like int(''.join([str(i) for i in coefficients])). This method works for all bases less than 10, since bases after ten require letters (but then again, you could use look at the items in coefficients to get the letters).
If you just want to solve the problem "number to binary string", you could use simple python:
def to_binary(n):
return "{:b}".format(n)
Simply use bin() instead.
def to_binary(n):
return(bin(n)[2:])
to_binary(6)
'110'

How many times should I loop to cover all cases of possible sums?

I am trying to solve this competitive programming problem using python3. The problem asks, given an array of size n, split the array into three consecutive, contiguous parts such that the first part has maximum sum and equals the sum of the third part. The elements in the array are positive integers.
My approach:
inputN = int(input())
inputString = input()
usableString = stringToList(inputString)
counting = 0
sum1 = usableString[0]
sum3 = usableString[-1]
maxSum1 = 0
countFromLeft = 1
countFromRight = 2
while counting < inputN-1:
if sum1 > sum3:
sum3 += usableString[-countFromRight]
countFromRight += 1
elif sum3 > sum1:
sum1 += usableString[countFromLeft]
countFromLeft += 1
elif sum1 == sum3:
maxSum1 = sum1
sum1 += usableString[countFromLeft]
countFromLeft += 1
counting += 1
print(maxSum1)
We read in the array elements and store them in a list usableString.
We set two variables sum1 and sum3 to the first and last elements of the list respectively.
We set a variable to keep track of the maximum sum of the first part of the list.
Finally, we set a variable counting to 0 which will represent the number of elements we have added from the list into sum1 or sum3.
The rest of the logic is in the while loop, which just checks if sum1 is larger than sum3 or the other way around and otherwise if they equal. After each iteration we add 1 to counting as an extra element has been included in a part. The while loop should stop when the number of elements used (i.e counting) is equal to the number of elements in the array - 1, since we added the first and last elements before entering the loop, which makes (array - 2), however, we still need to loop one additional time to check if sum1 and sum3 are equal.
I checked your submitted algorithm, and the problem is your stringToList function:
def stringToList(s):
list=[]
for elem in s:
if elem != " ":
list.append(int(elem))
return list
As far as I can tell, your main algorithm is completely fine, but stringToList does one crucial thing incorrectly:
>>> stringToList('2 4 6 8 10')
[2, 4, 6, 8, 1, 0]
# should be
[2, 4, 6, 8, 10]
As it treats each character individually, the two digits of 10 are turned into 1, 0. A simpler method which performs correctly would be to do the following:
# explanation
>>> input()
'2 4 6 8 10'
>>> input().split(' ')
['2', '4', '6', '8', '10']
>>> map(int, input().split(' ')) # applies the int function to all elements
<map object at 0x...>
>>> list(map(int, input().split(' '))) # converts map object into list
[2, 4, 6, 8, 10]
Sorry it took so long, I ended up making my own algorithm to compare to yours, ran my own tests, and then ran your code with the input to list method I just explained, and figured the only difference was your stringToList function. Took a while, but I hope it helps!
Just for the fun, here's my algorithm and turns out it was pretty similar to yours!
array = [1, 3, 2, 1, 4]
n = len(array)
slice = [0, n]
sum = [array[0], 0]
bestSum = 0
while slice[0] < slice[1]-1:
i = 0 if (sum[0] < sum[1]) else 1
slice[i] += 1-(2*i)
sum[i] += array[slice[i]]
if sum[0] == sum[1]: bestSum = sum[0]
# print(array[ : slice[0]+1], array[slice[0]+1 : slice[1]], array[slice[1] : ])
print(bestSum)

Finding subset List of Python List based on an input integer

I want a subset list from input List based on input integer value.
For Example:
Input List: [3,7,9,11,12]
Input Value: 2
Output List: [1,7,9,11,12]
# 2 is subtracted from first element of list
Input List: [3,7,9,11,12]
Input Value: 5
Output List: [5,9,11,12]
#5 is subtracted from list in sequence manner, first 3 is subtracted then remaining 2 is subtracted from 7 hence output is [5,9,11,12]
Use numpy.cumsum() if modules are allowed:
import numpy as np
input_list = np.asarray([3, 7, 9, 11, 12])
input_integer = 5
output_list = input_list[input_list.cumsum() > input_integer]
output_list[0] -= input_integer - input_list[input_list.cumsum() <= input_integer].sum()
print(output_list)
Output:
[ 5 9 11 12]
What i did there:
Since total sum is to be subtracted from starting, using cumulated sum will tell you where to crop the list from.
Then set the first element = first elem - (input_integer - cropped list's sum)
Recursive solution:
def subfrom( lst, n ):
if n<=0 or lst == []:
# No change necessary
return lst
if lst[0] <= n:
# First element gets removed
# Return the list you get by removing the leftover from the rest of the list
return subfrom( lst[1:], n-lst[0] )
# Reducde first element
return [lst[0]-n] + lst[1:]
Another solution:
# First set of test variables
list1 = [3,7,9,11,12]
input1 = 2
# Second set of test variables
list2 = [3,7,9,11,12]
input2 = 5
def eval_list(input_value, iterable, output = None):
if output is None:
output = []
for i, v in enumerate(iterable):
current = iterable[i]
if input_value > 0:
if v <= input_value:
input_value -= current
else:
current -= input_value
input_value = 0
output.append(current)
else:
output.append(current)
return output
Run for each data set and output results:
res1 = eval_list(input1, list1)
res2 = eval_list(input2, list2)
print(f"Set 1: {res1}")
print(f"Set 2: {res2}")
Output:
Set 1: [1, 7, 9, 11, 12]
Set 2: [5, 9, 11, 12]

Modify all integers in 2d list and make them even

When I run this through the visualizer it only modifies the first element in the 2d list. How do I make it so that the it runs throught the entire list.
def make_even(xss):
for i in range(len(xss)):
for j in range(len(xss)):
if xss[i][j] % 2!= 0:
xss[i][j] += 3
return xss
xss = [[1,2,3],[],[4,5]]
make_even(xss)
print(xss)
So first off you need to correct your indentation in your code:
def make_even(xss):
for i in range(len(xss)):
for j in range(len(xss)):
if xss[i][j] % 2!= 0:
xss[i][j] += 3
return xss
However, because both your loops use len(xss), they expect an array of 3 lists each with 3 elements. If you'd want each list to have variable numbers of elements you should do this instead:
def make_even(xss):
for i in range(len(xss)):
for j in range(len(xss[i])):
if xss[i][j] % 2!= 0:
xss[i][j] += 3
return xss
Which returns: [[4, 2, 6], [], [4, 8]]
However, there are two obvious changes I would make:
Your if statement should be if xss[i][j] % 2 == 1, since it's more readable.
You can make a number even by adding 1. (If 3 is required for your specs that's fine).
Also, this is totally doable in a single line (any line would work):
# List comprehensions only
xss = [[(x + 3 if x % 2 == 1 else x) for x in row] for row in xss]
# map and lamdbas (returns lists)
xss = list(map(lambda row: list(map((lambda x: x + 3 if x % 2 == 1 else x),row)), xss))
# map and lamdbas (returns iterables)
xss = map(lambda row: map((lambda x: x + 3 if x % 2 == 1 else x),row), xss)
Although personally, I think the list comprehensions is the easiest to read.

Resources