Getting the list out of the recursion - python

The temp in base case is the answer i need.It should be to be appended to the final.But I am ending up with list of empty lists.Any suggestion?
def recur(st,end,a,temp,k,final):
if sum(temp) == k:
final.append(temp)
print(temp)
return
if sum(temp)>k:
return
if st==end-1:
return
st+=1
temp.append(a[st])
recur(st,end,a,temp,k,final)
temp.pop()
recur(st,end,a,temp,k,final)
for _ in range(int(input())):
a = list(map(int,input().split()))
k = int(input())
a.sort()
final = []
temp = []
recur(-1,len(a),a,temp,k,final)
print(final)

I am ending up with list of empty lists.
That is likely due to this statement:
final.append(temp)
You're appending the list temp to final but temp will continue to change after this happens and final will eventually contain one or more pointers to the last value of temp, not it's value when you appended it. To get that, you need to append a copy of temp that won't change:
final.append(list(temp)) # make a copy and stash it away
Generally, I agree with #patmcb regarding our inability to guess what this code is trying to do. However, structurally, I'd expect a properly designed recursive function to look more like:
def recur(start, end, array, temp, target):
total = sum(temp)
if total == target:
return [list(temp)] # a list containing a copy of temp
if total > target or start == end - 1:
return []
start += 1
temp.append(array[start])
result = recur(start, end, array, temp, target)
temp.pop()
return result + recur(start, end, array, temp, target)
for _ in range(int(input())):
a = sorted(map(int, input().split()))
k = int(input())
print(recur(-1, len(a), a, [], k))
OUTPUT
> python3 test.py
1
5 10 13 2 4 6
21
[[2, 4, 5, 10], [2, 6, 13], [5, 6, 10]]
>

Related

How can I move zeroes to the end of a list?

I have an array of integers like:
nums = [0, 1, 0, 3, 12]
I want to move all '0's to the end of it, while maintaining the relative order of the non-zero elements. So the desired output is [1, 3, 12, 0, 0].
I made the following attempts:
temp = 0
for i in range(len(nums)):
if nums[i] == 0:
nums.pop(i)
temp += 1
print(temp)
In this code, I got an error saying that nums[i] has an index out of range. Why? len(nums) == 5, so the i values should all be valid.
nums = [0,1,0,3,12]
nums.sort()
temp = 0
for i in range(len(nums)-1):
if nums[i] == 0:
print(nums[i])
temp +=1
nums.pop(i)
print(nums)
for _ in range(temp):
nums.append(0)
print(nums)
With this code, the first print gives an output of [0, 1, 3, 12], so in the final result, not all of the zeroes are moved. Why were they not all popped by the first loop?
I think one way you can get the desired output is to separate the nums list into two list that doesn't contain zeros and one does using list comprehension and concat the two list together
nums = [0,1,0,3,12]
new_list = [n for n in nums if n != 0] + [n for n in nums if n == 0]
Edit: per #DanielHao's suggestion, you can also use sorted key lambda with lambda x: not x which will then interprets zeroes as 1 and non-zeroes as 0 when sorting the list
nums = [0,1,0,3,12]
nums[:] = sorted(nums, key=lambda x: not x)
nums = [0, 1, 0, 3, 12]
temp =0
new_nums=[]
for x in range(0,len(nums)):
if(nums[x]==0):
temp +=1
else:
new_nums.append(nums[x])
while(temp != 0):
new_nums.append(0)
temp -=1
print(new_nums)
This code work efficiently to produce desired output.
Q1) When you pop out the item, the length of nums is decreased. For loops will not adjust the range being iterated over, so in this case range(len(nums)) will always be range(5) as this was the original length. This means that nums[4] is called, which results in an index error because the item that used to be at this index has moved backwards in the list due to the removal of prior values.
A solution is to use a while loop, as the condition i < len(nums) will be checked at every iteration. You will have to manually increment i.
Q2) If the indices of values in the list decreases as items are popped, some values will be skipped.
A solution in tandem with a while loop is to only increment i if the condition nums[i] == 0 is not met.
nums = [0,1,0,3,12]
nums.sort()
temp = 0
i = 0
while i < len(nums):
if nums[i] == 0:
print(nums[i])
temp += 1
nums.pop(i)
else:
i += 1
print(nums)
for _ in range(temp):
nums.append(0)
print(nums)
There are definitely easier ways to solve the same problem, as shown in other solutions, but I hope this way is easy to understand.
1] You are popping the list element so the list length changes hence getting out of index error
2] Code:
nums = [0,1,0,3,12]
# Get count of 0's
count = nums.count(0)
# List without 0's
nums = [ i for i in nums if i!=0 ]
# Add 0's to the end
[nums.append(0) for i in range(count)]
print(nums)

delete odd numbers in a range

I'm trying to create a code which deletes the odd numbers in a user-defined range (for example, between 4 and 10). So far I have this:
def even(x,y):
if x > y:
return None
else:
s = list(range(x, y+1))
for i in s:
if s[i]%2!=0:
del s[i]
return s
even(4,10)
When I run the code, it returns [4, 5, 6, 7, 8, 10] instead of [4, 6, 8, 10]. Any idea why?
It makes little sense to create a larger collection and then remove the items you don't want.
I suspect it would be better if you just create the list with what you want up front:
def even(lo, hi):
if lo > hi: return None # although [] may make more sense
return [item for item in range(lo, hi + 1) if item % 2 == 0]
The reason why I state that it may be better to return [] for the case of lo > hi is because that's what gets returned for other edge cases, such as even(3,3).
This gives what you desire, as per the following transcript:
>>> def even(lo, hi):
... if lo > hi: return None
... return [item for item in range(lo, hi + 1) if item % 2 == 0]
...
>>> even(4, 10)
[4, 6, 8, 10]
There are 3 things wrong with your code.
Using s[i] accesses the ith item of the list, but i is already holding the list item because you did for i in s::
>>> s = list(range(4, 11))
>>> s
[4, 5, 6, 7, 8, 9, 10]
>>> for i in s:
... print(i)
...
4
5
6
7
8
9
10
What your loop is actually checking with s[i] is this:
>>> for i in s:
... print(s[i])
...
8 # i=4, s[4]
9 # i=5, s[5]
10 # i=6, s[6]
When you do find an odd number (s[5]=9, 9%2 != 0), you immediately break out of the loop because of the return s. So, your loop will only remove the first odd number it finds, then immediately break out of the loop.
Maybe it's just wrongly indented, but the return s should be at the end of the function, not inside the loop.
You are removing items from the list while you are iterating over it. That is never a good idea, because that will mess up the loop.
>>> s = list(range(4, 11))
>>> for idx, i in enumerate(s):
... print(i)
... if i%2 != 0:
... print("removing i")
... del s[idx]
...
4
5
removing i
7 # notice that 6 was now skipped after removing 5
removing i
9 # notice that 8 was now skipped after removing 7
removing i
With that said, the correct way is to iterate over the input list but the result/output should be on a different list. That way, the loop does not get messed up. The simplest (and most "pythonic") way is by using list comprehension:
def even(x,y):
if x > y:
return None
else:
s = list(range(x, y+1))
return [d for d in s if d % 2 == 0]
Or, you can manually loop using while and then track the correct list index:
def even(x,y):
if x > y:
return None
else:
s = list(range(x, y+1))
idx = 0
while idx < len(s):
if s[idx]%2!=0:
del s[idx]
# after this, s[idx] now points to the next item
else:
idx += 1
# move to the next item
return s
This is the right code. you can remove from list by items and del by index in python:
def even(x,y):
if x > y:
return None
else:
s = list(range(x, y+1))
for i in s:
if i%2 != 0:
s.remove(i)
return s
even(4,10)

Appending Elements of a String into a List (python)

This program is designed to take a string consisting of numbers (any length) and outputting the contents of the string into a list, one digit at a time. Should a number, x, be less than or equal to the preceding number, y, the number x is to be inserted into a sublist. Until a number, z, is greater than y, everything between x and z will also be added to the sublist. Here is the code
def numbers_in_lists(string):
final = []
temp = []
prev = 0
for i in range(len(string)):
value = int(string[i])
if value<=prev:
temp.append(value)
else:
if temp != []:
final.append(temp)
temp = []
final.append(value)
prev = int(string[i])
print final
return final
To test this function, add the following to the remainder of the code:
string = '543987'
result = [5,[4,3],9,[8,7]]
print repr(string), numbers_in_lists(string) == result
string= '987654321'
result = [9,[8,7,6,5,4,3,2,1]]
print repr(string), numbers_in_lists(string) == result
string = '455532123266'
result = [4, 5, [5, 5, 3, 2, 1, 2, 3, 2], 6, [6]]
print repr(string), numbers_in_lists(string) == result
string = '123456789'
result = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print repr(string), numbers_in_lists(string) == result
After the code creates and returns a sublist, it finds a new maximum value and doesn't add anything else to the list, thus leaving the final list incomplete.
If I test with the string '543987' the prefered result is [5,[4,3],9,[8,7]] whereas my result is [5,[4,3],9]
You need to check temp after the for loop ends, it might still contain something:
def numbers_in_lists(string):
final = []
temp = []
prev = 0
for digit in string:
value = int(digit)
if value<=prev:
temp.append(value)
else:
if temp:
final.append(temp)
temp = []
final.append(value)
prev = int(digit)
if temp:
final.append(temp)
print final
return final
I also slightly re-worked your for loop (no need to use indexed access) and replaced temp != [] with temp (see here).

list of list concept in python

I solved the below problem using nested while loops. Is there a way to solve the problem in a simple, Pythonic way?
Question:
Define a procedure that takes in a string of numbers from 1-9 and outputs a list with the following parameters:
Every number in the string should be inserted into the list.
If a number x in the string is less than or equal to the preceding number y, the number x should be inserted into a sublist.
Continue adding the following numbers to the sublist until reaching a number z that is greater than the number y.
Then add this number z to the normal list and continue.
They are comparing the subsequent against the previous digit.
For example:
string = '543987'
result = [5,[4,3],9,[8,7]]
string= '987654321'
result = [9,[8,7,6,5,4,3,2,1]]
string = '455532123266'
result = [4, 5, [5, 5, 3, 2, 1, 2, 3, 2], 6, [6]]
My code:
def numbers_in_lists(string):
array = []
for i in string:
array.append(int(i))
temp_list = []
final_list = [array[0]]
i = 0
while i+1 < len(array):
if array[i] >= array[i+1]:
j = 0
while j+1 < len(array[i:]) and array[i] >= array[i:][j+1]:
temp_list.append(array[i:][j+1])
j += 1
final_list.append(temp_list)
i += len(temp_list)
temp_list = []
else:
final_list.append(array[i+1])
i += 1
#print final_list
return final_list
string = '543987'
print numbers_in_lists(string)
[5, [4, 3], 9, [8, 7]]
You can certainly simplify the approach; I would do it as follows:
def numbers_in_lists(string):
"""Describe what it does here!"""
output = []
sublist = []
for num in map(int, string):
if not output or num > output[-1]:
if sublist:
output.append(sublist)
sublist = []
output.append(num)
else:
sublist.append(num)
if sublist:
output.append(sublist)
return output
In use:
>>> numbers_in_lists('543987')
[5, [4, 3], 9, [8, 7]]
>>> numbers_in_lists('987654321')
[9, [8, 7, 6, 5, 4, 3, 2, 1]]
>>> numbers_in_lists('455532123266')
[4, 5, [5, 5, 3, 2, 1, 2, 3, 2], 6, [6]]
This is the solution, you should consider.
num = '455532123266'
final_list = [];
prev = 0
sublist = []
for n in num:
n = int(n)
if (n > prev):
if (sublist != []):
final_list.append(sublist)
sublist = []
final_list.append(n)
else:
sublist.append(n)
prev = n
if sublist != []:
final_list.append(sublist)
print final_list
[4, 5, [5, 5, 3, 2, 1], 2, 3, [2], 6, [6]]
well... Adding my 2 cents :-)
def custom_func(input_string):
if not input_string:
return []
value = input_string[0]
output_list = [int(value)]
for char in input_string[1:]:
if char > value:
# Encountered a value higher than the past maximum
output_list.append(int(char))
else:
if value == str(output_list[-1]):
# First value that is lesser than the past maximum
output_list.append([int(char)])
else:
# nth value which is lesser than the past maximum
output_list[-1].append(int(char))
value = char # updating the past maximum
return output_list
I would consider doing it in more functional way.
def solve(input):
pairs = zip(input, input[1:])
sublist = [False] + map(lambda x: x[0] > x[1], pairs)
result = []
for (val, to_sublist) in zip(input, sublist):
if not to_sublist:
result.append(val)
else:
if isinstance(result[-1], list):
result[-1].append(val)
else:
result.append([val])
return result
This is allows for separation of checking to_sublist predicate and actual building of resulting data structure. To my understanding first number never goes to sublist so it always starts with False.
The problem is not very well-defined, in that the example input does not exactly clarify 2 issues:
What should happen with '567' - should there be empty list after each number
The example cannot tell if you are comparing the subsequent against the previous digit or the first digit of the decreasing subsequence!
Thus here is my take, it is not necessarily the most pythonic, but I couldn't come up with more pythonic solution.
def numbers_in_lists(string):
current_min = -1 # larger than any digit
rv = []
current_list = []
def push_sublist():
if current_list:
largest = current_list.pop(0)
rv.extend([largest, current_list])
for digit in map(int, string):
if digit > current_min:
push_sublist()
current_list = []
current_min = digit
current_list.append(digit)
push_sublist() # if remaining
return rv
As I suspected, the question was not at all clear. Considering how the example code worked, I devised a new algorithm
def numbers_in_lists(string):
current_min = -1 # larger than any digit
rv = []
current_list = []
def push_sublist():
if current_list:
largest = current_list.pop(0)
rv.append(largest)
if current_list:
rv.append(current_list)
for digit in map(int, string):
if digit > current_min:
push_sublist()
current_list = []
current_min = digit
current_list.append(digit)
push_sublist() # if remaining
return rv
The simplest solution I could think of that follows the actual problem statement is:
def numbers_in_lists(string):
output = []
sublist = []
for number in [int(c) for c in string]: # Every number in the string should be inserted into the list.
if output and number <= output[-1]:
"""
- If a number x in the string is less than or equal
to the preceding number y, the number x should be
inserted into a sublist.
- Continue adding the following numbers to the sublist
until reaching a number z that is greater than the number y.
"""
sublist.append(number)
else:
"""
- Then add this number z to the normal list and continue.
"""
if sublist:
output.append(sublist)
sublist = []
output.append(number)
if sublist:
output.append(sublist)
return output
One other way of doing it... Might be confusing though
_val = int(string[0])
my_lis = [_val]
temp_li = []
for i in string[1:]:
_cval = int(i)
if _cval > _val:
if temp_li:
my_lis.append(temp_li[:])
temp_li = []
my_lis.append(_cval)
_val = _cval
else:
temp_li.append(_cval)
_val = temp_li[0]
if temp_li: my_lis.append(temp_li[:])# last value
print string
print my_lis
Mine is the lazy one:
def num_and_sublist_generator(iterable):
start = -1
sublist = []
for n in iterable:
if n > start:
if sublist:
yield sublist
sublist = []
start = n
yield n
else:
sublist.append(n)
if sublist:
yield sublist
def numbers_in_lists(string):
return list(num_and_sublist_generator(map(int, string)))

Selection Sort (low to high) python

I am trying to write a selection sort algorithm for sorting lists of numbers from lowest to highest.
def sortlh(numList):
if type(numList) != list:
print("Input must be a list of numbers.")
else:
inf = float("inf")
sortList = [0]*len(numList)
count = 0
while count < len(numList):
index = 0
indexLowest = 0
lowest = numList[index]
while index < (len(numList) - 1):
if numList[index + 1] < numList[index]:
lowest = numList[index + 1]
indexLowest = index + 1
index = index + 1
else:
index = index + 1
sortList[count] = lowest
numList[indexLowest] = inf
count = count + 1
return sortList
When I run this code on:
sortlh([9,8,7,6,5,4,3,2,1])
I get (as expected):
[1, 2, 3, 4, 5, 6, 7, 8, 9]
However, when I try another example, I get:
sortlh([1,3,2,4,5,7,6,9,8])
[8, 6, 9, 2, 4, 5, 7, 1, 3]
Does anyone see what is going on here?
Here is how I would suggest rewriting your program.
def sortlh(lst_input):
lst = list(lst_input) # make a copy of lst_input
i = 0
while i < len(lst):
j = i + 1
i_lowest = i
lowest = lst[i_lowest]
while j < len(lst):
if lst[j] < lowest:
i_lowest = j
lowest = lst[i_lowest]
j += 1
lst[i], lst[i_lowest] = lst[i_lowest], lst[i] # swap
i += 1
return lst
test = [9,8,7,6,5,4,3,2,1]
assert sortlh(test) == sorted(test)
test = [1,3,2,4,5,7,6,9,8]
assert sortlh(test) == sorted(test)
We don't test the type of the input. Anything that acts like a list will work, and even an iterator will work.
We don't "mutate" the original input list. We only work on a copy of the data.
When we find the lowest number, we swap it with the first number, and then only look at the remaining numbers. Thus we have less work to do on each loop as we have fewer and fewer unsorted numbers.
EDIT:
If you are a beginner, this part might seem too tricky. If it confuses you or you don't like it, just ignore it for now.
This is a more-advanced way to solve this problem in Python. The inner loop simply finds the lowest number and the index of the lowest number. We can use the Python built-in function min() to do this!
We build a "generator expression" that loops over the list, yielding up tuples. Each tuple is the number and its position. Since we want lower numbers to sort lower, we put the number first in the tuple so that min() can properly compare the tuples. Then min() will find the lowest tuple and we get the value and index.
Also, the outer loop is now a for loop with enumerate rather than a while loop using indexing.
def sortlh(lst_input):
lst = list(lst_input) # make a copy of lst_input
for i, x in enumerate(lst):
lowest, i_lowest = min((n, j) for j, n in enumerate(lst) if j >= i)
lst[i], lst[i_lowest] = lst[i_lowest], lst[i] # swap
return lst
test = [9,8,7,6,5,4,3,2,1]
assert sortlh(test) == sorted(test)
test = [1,3,2,4,5,7,6,9,8]
assert sortlh(test) == sorted(test)

Categories

Resources