implementation error in Python recursive expression - python

I'm solving the problem.
You have to leave the last list, but the previous list is printed out again.
def merge(xs,ys):
# xs, ys, ss = xs, ys, []
xs, ys, ss = xs[:], ys[:], []
while xs!=[] and ys!=[]:
if xs[0] <= ys[0]:
ss.append(xs[0])
xs.remove(xs[0])
else:
ss.append(ys[0])
ys.remove(ys[0])
ss.extend(xs)
ss.extend(ys)
return ss
accumulator = []
remain = []
def merge2R(xss):
if len(xss)% 2 != 0 :
OExcept = len(xss)-1
remain.append((xss[OExcept]))
xss.remove(xss[OExcept])
if xss != []:
accumulator.append(merge(xss[0],xss[1]))
xss.remove(xss[0])
xss.remove(xss[0])
return merge2R(xss)
else:
return accumulator + remain
The result comes out like this.
How can I fix it?
>>> merge2R([[2],[1,3],[4,6,7],[5,8],[9]])
[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3], [4, 5, 6, 7, 8], [9]]
Desired result value:
>>> merge2R([[2],[1,3],[4,6,7],[5,8]])
[[1,2,3], [4,5,6,7,8]]
>>> merge2R([[2],[1,3],[4,6,7],[5,8],[9]])
[[1,2,3], [4,5,6,7,8], [9]]

Your code was working, you just needed to reset accumulator and remain
def merge2R(xss):
# Declare use of globals
global remain
global accumulator
if len(xss) % 2 != 0:
OExcept = len(xss)-1
remain.append((xss[OExcept]))
xss.remove(xss[OExcept])
if xss != []:
accumulator.append(merge(xss[0], xss[1]))
xss.remove(xss[0])
xss.remove(xss[0])
return merge2R(xss)
else:
x = accumulator + remain
# Must reset accumulator and remain
accumulator = []
remain = []
return x
Because you initialise both arrays as empty, then append to them:
# Remain
remain.append((xss[OExcept]))
# Accumulator
accumulator.append(merge(xss[0], xss[1]))
After you have finished with the data in those arrays (at end of function) you need to discard it:
accumulator = []
remain = []
The result of not discarding these arrays is evident when calling the function with the same argument multiple times:
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
[[1, 2, 3]]
[[1, 2, 3], [1, 2, 3]]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]

Related

Trying to write a combinations function in Python on my own, not working

I'm trying to solve this problem here: https://codingbat.com/prob/p252079?parent=/home/peter#norvig.com
In math, a "combination" of a set of things is a subset of the things. We define the function combinations(things, k) to be a list of all the subsets of exactly k elements of things. Conceptually, that's all there is, but there are some questions to settle: (A) how do we represent a subset? (B) What order are the elements within each subset? (C) What order to we list the subsets? Here's what we will agree to: (A) a subset will be a list. (B) The order of elements within a list will be the same as the order within 'things'. So, for example, for combinations([1, 2, 3], 2) one of the subsets will be [1, 2]; whereas [2, 1] is not a subset. (C) The order of subsets will be lexicographical or sorted order -- that is, combinations([1, 2, 3], 2) returns [ [1, 2], [1, 3], 2, 3] ] because [1, 2] < [1, 3] < [2, 3]. You might want to use the function 'sorted' to make sure the results you return are properly ordered.
combinations([1, 2, 3, 4, 5], 2) → [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
combinations([1, 2, 3], 2) → [[1, 2], [1, 3], [2, 3]]
combinations([1, 2, 3, 4, 5, 6], 5) → [[1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 5, 6], [1, 2, 4, 5, 6], [1, 3, 4, 5, 6], [2, 3, 4, 5, 6]]
Here's my code:
def combinations(things, k):
if k == 0 or k == len(things):
return [things]
elif len(things) < k:
return
else:
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for i in range(len(combinations(things[1:], k - 1))):
firstelement = [things[0]]
firstelement += combinations(things[1:], k - 1)[i]
finalcomb.append(firstelement)
for j in range(len(combinations(things[1:], k))):
finalcomb.append(combinations(things[1:], k)[j])
return finalcomb
However, this is the output:
Haven't hit 10 reputation yet so it's a link to the error. I'm not sure what I did wrong, can anybody help me out? Thank you so much.
The problem is this. When k == 0 it shouldn't return [things]. It should return an empty array. Similar to when len(things) < k:. This is because, when k == 0, it means we that we have already found all the numbers for that specific combination.
But there's one more problem. We're returning an empty array. However, in the for loops, we're iterating over the returned array. So if the array is empty, nothing happens. So what we should really return is an empty 2D array. I won't go into too much detail about what the problem is since it's better for you to try and understand why it's not working. Try adding print statements inside and outside the for loops.
Anyway, the working code looks like this:
def combinations(things, k):
if k == len(things):
return [things[:]]
if len(things) < k or k == 0:
return [[]]
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for comb in subcomb1:
firstelement = [things[0]]
firstelement += comb
finalcomb.append(firstelement)
finalcomb += subcomb2
return finalcomb
Note a few things:
Use the variables you've already assigned (I'm assuming you forgot about them)
Lists can be concatenated using +, similar to strings. If you return within an if statement, you don't need an else for the next line since if the if statement is satisfied, it would definitely not go to the else.
You simply can try using itertools:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 2):
output.append(list(nums))
print(output)
output:
[[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
For 3 nums:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 3):
output.append(list(nums))
print(output)
Output:
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5]]

Join list of lists into a delimiter separated list of lists

I have the following list of lists and a delimiter:
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
I'd like to mimic the string.join() behavior.
expected output is:
lst = [[1, 2, 3], ['delim'], [4, 5], ['delim'], [6]]
I tried:
from itertools import chain
n = 2
ele = 'x'
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(chain(*[lst[i:i+n] + [ele] if len(lst[i:i+n]) == n else lst[i:i+n] for i in xrange(0, len(lst), n)]))
# which flattens the list and then inserst elements every second position,
# which doesn't help if the lists inside the list are of different length.
Try this:
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
place_holder = []
for i in lsts:
place_holder.append(i)
place_holder.append(delim)
place_holder.pop() # Pop the last element :)
print(place_holder)
You can use slice assignment
def list_join(seq, delim):
res = [delim]*(len(seq) * 2 - 1)
res[::2] = seq
return res
delim = ['delim']
# empty list
lsts = [[]]
print(list_join(lsts, delim))
# even length
lsts = [[1, 2, 3], [4, 5], [6], [7]]
print(list_join(lsts, delim))
# odd length
lsts = [[1, 2, 3], [4, 5], [6]]
print(list_join(lsts, delim))
Output
[[]]
[[1, 2, 3], ['delim'], [4, 5], ['delim'], [6], ['delim'], [7]]
[[1, 2, 3], ['delim'], [4, 5], ['delim'], [6]]
Here is my solution. It looks like the shortest code.
for i in range(len(lsts) - 1, 0, -1):
lsts.insert(i, delim)
print(lsts)
This uses a simple for loop that validates the position on the item isn’t the last item before adding the delimiter.
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
output = []
for i, l in enumerate(lsts):
output.append(l)
if i < (len(lsts) - 1):
output.append(delim)
After trying to solve it for quite a while and reviewing the other answers, I came up with an other alternative as well.
lsts = [[1, 2, 3], [4, 5], [6]]
delim = ['delim']
[x for t in zip(lsts,[delim]*len(lsts)) for x in t][:-1]
# Out[44]: [[1, 2, 3], ['delim'], [4, 5], ['delim'], [6]]

python while loop does not show correct output?

This is quite strange, I am quite sure that the code works without the while loop:
target = [[1],]
add = [2,4]
count = 0
while count < 2:
temp = []
for i in target:
temp += [i, i]
target = temp[:]
print('before', target)
idx = 0
while idx < len(target):
target[idx].append(add[idx])
idx += 1
print('after', target)
add += add
count += 1
Here I have target as a nested list that contains number, I have add just as a list of numbers. My idea is to double the target every loop, and add one item from add to one sub-list of target and double the add afterwards.
I am getting the result:
before [[1], [1]]
after [[1, 2, 4], [1, 2, 4]]
before [[1, 2, 4], [1, 2, 4], [1, 2, 4], [1, 2, 4]]
after [[1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4]]
if you look at the before and after, the whole add was added to each sub-list of target, instead of adding add[0] to target[0], then add[1] to target[1] showed below as my expectation:
before [[1], [1]]
after [[1, 2], [1, 4]]
before [[1, 2], [1, 4], [1, 2], [1, 4]]
after [[1, 2, 2], [1, 4, 4], [1, 2, 2], [1, 4, 4]]
without the outer while loop:
target = [[1],[1]]
add = [2,4]
count = 0
idx = 0
while idx < len(target):
target[idx].append(add[idx])
idx += 1
print(target)
# >>>
[[1, 2], [1, 4]]
Can't really understand why
The problem is in this block of code:
temp = []
for i in target:
temp += [i, i]
target = temp[:]
When it loops over target, it pulls out each item, in this case a list ([1]). This specific list (not copies) is then added twice to the temp list. What you need to do is copy when building temp:
temp = []
for i in target:
temp += [i[:], i[:]]
target = temp

sorting python list in recursive manner

As input I will be getting lists of lists which can up to n-levels and it will vary every time. Suppose, I have a list
[[2, 1, 3], 4, [2, 3], 7, 1, [9, [4, 2], 5]]
here I want to sort this list and expected output is
[1, 4, [2, 3], [1, 2, 3], 7, [5, [2, 4], 9]]
Here, first sorting is happening based of elements and then based on sum of elements inside list.
code:
input_freq = [[2,1,3],4,[2,3],7,1,[9,[4,2],5]]
res = []
def sortFreq(input_freq):
elements = []
list_of_elements = []
for each in input_freq:
if isinstance(each, list):
print "list"
list_of_elements.append(each)
each.sort()
else:
elements.append(each)
elements.sort()
print elements
print list_of_elements
sortFreq(input_freq)
expected output:
[1, 4, [2, 3], [1, 2, 3], 7, [5, [4, 2], 9]]
but my code returns the wrong result:
[[1, 2, 3], [2, 3], [5, 9, [4, 2]]]
You'll have to work your way down to the nested levels first, then sort the parent levels as the recursive call returns. I'm going to assume you want to return a new list (and not sort in place):
def nested_sort(l):
def sort_key(e):
if isinstance(e, list):
return sum(sort_key(inner) for inner in e)
return e
return sorted(
[nested_sort(e) if isinstance(e, list) else e for e in l],
key=sort_key)
The sort key has to recursively sum nested lists, so this can be kind of expensive if you have many nested levels. In that it may be worth adding a cache based on the identity of the list being summed:
def nested_sort(l, _sum_cache=None):
if _sum_cache is None:
_sum_cache = {}
def sort_key(e):
if isinstance(e, list):
e_id = id(e)
if e_id not in _sum_cache:
_sum_cache[e_id] = sum(sort_key(inner) for inner in e)
return _sum_cache[e_id]
return e
return sorted(
[nested_sort(e, _sum_cache) if isinstance(e, list) else e for e in l],
key=sort_key)
Demo:
>>> nested_sort([[2, 1, 3], 4, [2, 3], 7, 1, [9, [4, 2], 5]])
[1, 4, [2, 3], [1, 2, 3], 7, [5, [2, 4], 9]]
Here is a solution that has the benefit of doing every sum only once. It is also quite short:
import operator
def sort_lol(lol):
srtd, sums = zip(*sorted((sort_lol(el) if isinstance(el, list) else (el, el)
for el in lol), key=operator.itemgetter(1)))
return list(srtd), sum(sums)
lst = [[2,1,3],4,[2,3],7,1,[9,[4,2],5]]
print(sort_lol(lst))
# ([1, 4, [2, 3], [1, 2, 3], 7, [5, [2, 4], 9]], 43)
# note that the function returns the sorted list and the total (43 here)

Insert an array in an array using loop

I write the following code to create an array like [[1,2,3],[2,2,3],[3,2,3]],
def f(X):
X[0]=X[0]+1
return X
L=[]
X=[1,2,3]
for i in range(0,3):
L=L+[X]
X=f(X)
print(L)
But it is printing [[4, 2, 3], [4, 2, 3], [4, 2, 3]]. Why it is happening and how to solve this using the function 'f'?
Thanks
If you have to use your function f, then try as follows:
l = []
x = [1, 2, 3]
def f(x):
x[0] = x[0] + 1
return x
for i in range(3):
l.append(x[:])
x = f(x)
Output:
>>> l
[[1, 2, 3], [2, 2, 3], [3, 2, 3]]

Categories