Using (trying to) recursion to reverse lists within a list - python

def is_list(p):
return isinstance(p, list)
def deep_reverse(p):
initial = []
for v, e in enumerate(p):
if is_list(e):
#print p[v][::-1]
initial.append(p[v][::-1])
deep_reverse(e)
return initial
p = [1, [2, 3, [4, [5, 6, [7, 8]]]]]
print deep_reverse(p)
I get [[[4, [5, 6, [7, 8]]], 3, 2]], expected at least (I haven't bothered to figure out how to not lose the very first list [1[...]] yet) [[[[6, 5, [8, 7]], 4], 3, 2]].
As you can see the code only reverses [ [2, 3]] --> [[3, 2]].
What did I do wrong? Haven't I though about?

This is how I would do it:
def deep_reverse(p):
return [deep_reverse(x) if isinstance(x, list) else x for x in p[::-1]]
p = [1, [2, 3, [4, [5, 6, [7, 8]]]]]
print deep_reverse(p) # [[[[[8, 7], 6, 5], 4], 3, 2], 1]

A more generic, Pythonic answer to this, based on Pavel Anossov's is as follows:
def deep_reversed(seq):
return [deep_reversed(x) if (isinstance(x, collections.Sequence) and
not isinstance(x, str)) else x
for x in reversed(seq)]
Note that this is for Python 3.x, in Python 2.x, you will want isinstance(x, basestring) instead to allow for Unicode strings.
This answer is a good one, as it will work correctly with any object that acts as a sequence - be it a list, a tuple, or a custom class. This means it's much more flexible.
Edit: If you wanted it to reverse strings internally:
def deep_reversed(seq):
for x in reversed(seq):
if isinstance(x, collections.Sequence):
if isinstance(x, str):
yield "".join(reversed(x))
else:
yield deep_reversed(x)
else:
yield x
Again, in 2.x, use isinstance(x, basestring).

There are already many nice solutions, but maybe this is the algorithm you are trying:
def is_list(p):
return isinstance(p, list)
def deep_reverse(p):
initial = p[::-1] # reverse this level
for v, e in enumerate(initial):
if is_list(e): # for all the sublist in this level
initial[v] = deep_reverse(e) # recursively call deep_reverse to reverse the sublist
return initial
p = [1, [2, 3, [4, [5, 6, [7, 8]]]]]
print deep_reverse(p)

In the recursive calls to deep_reverse(e) you are not using the returned value. It looks as though you are expecting it to modify the input list
You can change it to something like this:
def deep_reverse(p):
initial = []
for e in p[::-1]:
if is_list(e):
initial.append(deep_reverse(e)])
else:
initial.append(e)
return initial

This will solve your purpose:
import collections
def dr(p):
r=[]
for i in p:
if isinstance(i,collections.Iterable):
r.append(dr(i))
else:
r.append(i)
return r[::-1]

Related

How to find subsets from a set that product equals the target?

Let us say we have a list and target of:
list: [1,2,3,4,5] and target: 20
and we want to find total combinations to reach this, with multiplication, which is:
[1,4,5], [4,5], [2,5,2], [1,2,2,5]
I did this code, but I can't seem to know how to remove the ones so I have them too, I mean that I receive:
[1,4,5], [1,2,2,5].
But without [1], I can't seem to get it, I tried to "cheat" somehow to get it, but I can't since my code doesn't fit for it...
def Coin(target, lst, temp=[], comb=[]):
if target == 1:
comb.append(temp)
return comb
if len(lst) == 0:
return []
if target >= lst[0]:
if lst[0] > 1:
take=Coin(target/lst[0],lst,temp+[lst[0]],comb)
dont_take=Coin(target,lst[1:],temp,comb)
else:
take_1 = Coin(target, lst[1:], temp + [1], comb)
return take_1
return take
return comb
print(Coin(20, [1,2,3,4,5], [], []))
[[1, 2, 2, 5], [1, 4, 5]]
How to add the parts without 1? I don't need a solution, since as said, not homework, but practice for exam. Just a clue will be enough, I want to find it myself, but I need a clue for it.
Maybe you should combine
if lst[0] > 1:
else:
together, that means for 1 we should also decide whether take it or not.
This is much easier to do with a generator using yield than a function using return.
The difference is that you can only return once, while you can yield any number of times (including 0 if there are no solutions).
If you wish to return a list, you still can, like this:
def coin (target, lst):
return list(_coin(target, lst, 0)
def _coin (target, lst, i):
...
If that doesn't matter, the generator saves memory by not having to generate the whole list at once. And you simply:
def coin (target, lst, i=0):
... # Use yield as often as you want, all will be returned.
Second, you are running into the most common gotcha in Python. You are using mutable objects as defaults. If you're going to continue with your current approach you need to:
def coin(target, lst, temp=None, comb=None):
if temp is None:
temp = []
if comb is None:
comb = []
...
And third, you should get in the habit of following standard style conventions. In many ways, what the convention is doesn't matter that much. But that everyone is on the same page, does. Therefore you should try to follow the most common Python convention. In which the function should be named coin instead of Coin.
Edit:
The rules for the question is:
Positive integers only ( 0 not allowed ).
Number can appear once only ( at input ).
can not repeat numbers on list.
EG: [1,2,3,4], n=12 >> [1,12], [12,1], [3,4], [2,6], [1,3,4], [1,2,6].
NOT: [1,2,2,3], [2,2,3]
That is all I guess.
def coin_change_MULTI(num, lst):
if num == 1 and 1 not in lst:
return []
return Coin_MULTI(num, sorted(lst), [], [])
def Coin_MULTI(target, lst, temp=[], comb=[]):
if target == 1:
if big_than_target(1, lst):
return [[1]]
comb.append(temp)
return comb
if len(lst) == 0: return []
if target >= lst[0]:
if lst[0] > 1:
take=Coin_MULTI(target/lst[0],lst[1:],temp+[lst[0]],comb)
dont_take=Coin_MULTI(target,lst[1:],temp,comb)
return comb
else:
take_1 = Coin_MULTI(target, lst[1:], temp + [1], comb)
dont_take_1 = Coin_MULTI(target, lst[1:], temp, comb)
return comb
return take + dont_take
return comb
print(coin_change_MULTI(12, [2,4,6,12,7,3, 1]))
print(coin_change_MULTI(1, [2,4,6,12,7,3,1]))
print(coin_change_MULTI(1, [2,4,6,12,7,3]))
print(coin_change_MULTI(100, [2,4,6,12,7,3,1]))
print(coin_change_MULTI(576, [2,4,6,12,7,3,1]))
print(coin_change_MULTI(12096, [2,4,6,12,7,3,1]))
print(coin_change_MULTI(0, [2,4,6,12,7,3,1]))
print((coin_change_MULTI(24, [2,4,6,12,7,3,1])))
[[1, 2, 6], [1, 3, 4], [1, 12], [2, 6], [3, 4], [12]]
[[1]]
[]
[]
[[1, 2, 4, 6, 12], [2, 4, 6, 12]]
[[1, 2, 3, 4, 6, 7, 12], [2, 3, 4, 6, 7, 12]]
[]
[[1, 2, 3, 4], [1, 2, 12], [1, 4, 6], [2, 3, 4], [2, 12], [4, 6]]
Process finished with exit code 0

Using recursion to determine the index path of a nested function

Im trying to make a function which finds a value from a list (xs) using another list (index_list) as an index path.
My function should work like this:
xs = [[[1, 2], 3], [4, 5, [6, 7]], 8, [9, 10, 11]]
>>> recursive_index(xs, [1, 2, 0])
6
So far I have:
def recursive_index(xs: List, index_path):
if not index_path:
return 0
return recursive_index(xs, index_path[1:])
This however just returns 0 for everything, but I don't know what else the base case should be.
You're quite close, but you forgot that at each recursion you actually need to index the list so that you get further in at each recursion. This way, by the time you get to the base case, the variable xs will store the correct result and you can just return it.
This is what the code would look like:
def recursive_index(xs: List, index_path):
if not index_path:
return xs
return recursive_index(xs[index_path[0]], index_path[1:])
You want this:
def recursive_index(xs, index_path):
if not index_path:
# if path is exhausted just return current element
return xs
# use first index on current list and recurse with the remaining path
return recursive_index(xs[index_path[0]], index_path[1:])
Your recursive function should keep extracting the value from xs at the first index of index_path until there is no more index in the rest of the path:
def recursive_index(xs, index_path):
index, *rest = index_path
value = xs[index]
return recursive_index(value, rest) if rest else value
The accepted answer already explains how to fix your recursive function.
Note that an iterative function works just as well:
def iterative_index(xs, index_path):
for idx in index_path:
xs = xs[idx]
return xs
Or using reduce:
from functools import reduce
def reduce_index(xs, index_path):
return reduce(list.__getitem__, index_path, xs)
Testing:
xs = [[[1, 2], 3], [4, 5, [6, 7]], 8, [9, 10, 11]]
index_path = (1, 2, 0)
print( iterative_index(xs, index_path) )
# 6
print( reduce_index(xs, index_path) )
# 6

Python list comprehension with complex data structures

I'm trying to flatten some mixed arrays in Python using LC. I'm having some trouble figuring out how to structure it.
Here's the array's i'm trying to flatten
arr_1 = [1, [2, 3], 4, 5]
arr_2 = [1,[2,3],[[4,5]]]
I tried this methods for arr_1 but get "TypeError: 'int' object is not iterable"
print([item if type(items) is list else items for items in arr_1 for item in items])
So I decided to break it into parts to see where it's failing by using this
def check(item):
return item;
print([check(item) if type(items) is list else check(items) for items in [1, [2, 3], 4, 5] for items in arr_2])
Through the debugger I found that it's failing at the 2d array in
for items in [1, [2, 3], 4, 5]
I don't need the LC to be in one line but I just wanted to know how to do it in a single nested LC if its even possible.
Using an internal stack and iter's second form to simulate a while loop:
def flatten(obj):
return [x
for stack in [[obj]]
for x, in iter(lambda: stack and [stack.pop()], [])
if isinstance(x, int)
or stack.extend(reversed(x))]
print(flatten([1, [2, 3], 4, 5]))
print(flatten([1, [2, 3], [[4, 5]]]))
print(flatten([1, [2, [], 3], [[4, 5]]]))
Output (Try it online!):
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
To explain it a bit, here's roughly the same with ordinary code:
def flatten(obj):
result = []
stack = [obj]
while stack:
x = stack.pop()
if isinstance(x, int):
result.append(x)
else:
stack.extend(reversed(x))
return result
If the order doesn't matter, we can use a queue instead (inspired by 0x263A's comment), although it's less memory-efficient (Try it online!):
def flatten(obj):
return [x
for queue in [[obj]]
for x in queue
if isinstance(x, int) or queue.extend(x)]
We can fix the order if instead of putting each list's contents at the end of the queue, we insert them right after the list (which is less time-efficient) in the "priority" queue (Try it online!):
def flatten(obj):
return [x
for pqueue in [[obj]]
for i, x in enumerate(pqueue, 1)
if isinstance(x, int) or pqueue.__setitem__(slice(i, i), x)]

How to search binary tree nodes to get longest tree in python using ADT

T = [[[[], [3, []]], [5, [[[[], [6, []]], [2, [[], [1, []]]]], [4, [[], [3, [[], [7, []]]]]]]]], [2, [[], [8, []]]]]
is a representation of a binary tree.
THE ABOVE CODE FOR T IS LONG, SCROLL ACROSS FOR FULL CODE
I am looking for the longest tree whose nodes sum is a multiple of a given number.
Example given 7 the tree T above as searchMax(T, 7), [[2,5], [4,3], [7]] returns since it is the longest and also whose sum is a multiple of 7
I have defined the following code
def cons(x, y):
return [x, y]
def car(p):
return p[0]
def cdr(p):
return p[1]
nil = []
def makeBinTree(root, left, right):
return cons(left, cons(root, right))
emptyTree = nil
def isEmpty(tree):
if len(tree) < 1:
return True
else:
return False
def root(tree):
return tree[1][0]
def left(tree):
return tree[0][1]
def right(tree):
return [1][1]
def searchMax(tree, number):
but I just don't know where to go from there. Can you please help me with this.
I would write a function that iterates over all possible paths in the tree. Then I would iterate over those paths, and choose the ones that add up to a multiple of seven, and then from among those choose the longest one.
def isEmpty(tree):
if len(tree) < 1:
return True
else:
return False
def root(tree):
return tree[1][0]
def left(tree):
return tree[0]
def right(tree):
return tree[1][1]
def iter_all_paths(t):
if isEmpty(t):
return
yield [root(t)]
for child in (left(t), right(t)):
for path in iter_all_paths(child):
yield [root(t)] + path
def searchMax(t, x):
#find all paths that add up to a multiple of x
candidates = []
for path in iter_all_paths(t):
if sum(path) % x == 0:
candidates.append(path)
if not candidates:
return None
return max(candidates, key=len)
T = [[[[], [3, []]], [5, [[[[], [6, []]], [2, [[], [1, []]]]], [4, [[], [3, [[], [7, []]]]]]]]], [2, [[], [8, []]]]]
print(searchMax(T, 7))
Result:
[2, 5, 4, 2, 1]
This differs from your expected result, [2, 5, 4, 3, 7]. The two solutions have the same length so I assume it's fine to return one or the other. My solution returns the leftmost path if there is a tie in lengths.
Perhaps you're thinking "actually I don't want the longest path length, but rather the largest sum of nodes". Then [2, 5, 4, 3, 7] would beat [2, 5, 4, 2, 1] by seven. If that's what you want, you can change the final line of searchMax to return max(candidates, key=sum).
You might also be thinking "I would prefer for the result to be a list of lists, not a list of ints. I want each sublist to add up to a multiple of the number. Rather than [2, 5, 4, 3, 7], I want [[2, 5], [4, 3], [7]].
You could write a function that arranges a list into chunks that add up to the number, and call that function before returning from searchMax.
def chunk(seq, x):
result = [[]]
for item in seq:
result[-1].append(item)
if sum(result[-1]) % x == 0:
result.append([])
if not result[-1]:
del result[-1]
return result
#later, in searchMax...
return chunk(max(candidates, key=len), x)
Result:
[[2, 5], [4, 2, 1]]

Python deep reverse in a list

I have a nested list, and I need to reverse every element in the list. But I dont know whether the list is a list of list of list or not.
So example is:
p = [1, [2, 3, [4, [5, 6]]]]
print deep_reverse(p)
#>>> [[[[6, 5], 4], 3, 2], 1]
q = [1, [2,3], 4, [5,6]]
print deep_reverse(q)
#>>> [ [6,5], 4, [3, 2], 1]
What I have so far is:
def is_list(p):
return isinstance(p, list)
def deep_reverse(a):
a.reverse()
for i in a:
if is_list(i):
i.reverse()
print a
It works well for the second test, the q one, but doest work for the first test.
I am not sure do I need use a recursion to loop the whole thing? How can I modify my code? Thanks.
The reason your code doesn't work is because if i is a list of lists, you don't deep_reverse the lists within i.
You only need to change one line of your code to the following:
def is_list(p):
return isinstance(p, list)
def deep_reverse(a):
a.reverse()
for i in a:
if is_list(i):
deep_reverse(i) # <=== This is what changed
print a
def deep_reverse(lst):
try:
if len(lst) > 1:
return list(deep_reverse(item) for item in reversed(lst))
return lst
except TypeError:
return lst
def deep_reverse(L):
if L == []:
return L
elif type(L) == int:
return L
else:
return deep_reverse(L[1:]) + [deep_reverse(L[0])]
>>> print deep_reverse(p)
[[[[6, 5], 4], 3, 2], 1]
>>> print deep_reverse(q)
[[6, 5], 4, [3, 2], 1]
Hope this helps
>>> def deep_reverse(L):
for item in reversed(L):
if isinstance(item,list):
yield list(deep_reverse(item))
else:
yield item
>>> p = [1, [2, 3, [4, [5, 6]]]]
>>> q = [1, [2,3], 4, [5,6]]
>>> list(deep_reverse(p))
[[[[6, 5], 4], 3, 2], 1]
>>> list(deep_reverse(q))
[[6, 5], 4, [3, 2], 1]
Here is my solution
def is_list(p):
return isinstance(p, list)
def deep_reverse(p):
if p==[]:
return p
if not is_list(p[0]):
return deep_reverse(p[1:])+[p[0]]
else:
return deep_reverse(p[1:])+[deep_reverse(p[0])]
def deep_reverse(ls):
for i in ls:
if type(i)==list:deep_reverse(i)
ls.reverse()
here is a suggestion :
def deep_reverse(lst):
if isinstance(lst ,list):
if sum(1 for x in lst if isinstance(x, list)) == 0:
lst = lst[::-1]
return lst
else :
lst = lst[::-1]
lst = [deep_reverse(item) for item in lst]
return lst
else:
return lst
def is_list(p):
return isinstance(p, list)
def deep_reverse(p):
if p==[]:
return p
if not is_list(p):
return p
else:
return deep_reverse(p[1:])+[deep_reverse(p[0])]
test ok.
most elegant:
def deep_reverse(L):
""" assumes L is a list of lists whose elements are ints
Mutates L such that it reverses its elements and also
reverses the order of the int elements in every element of L.
It does not return anything.
"""
# Your code here
for i in L:
try:
deep_reverse(i)
except:
pass
L.reverse()
I am going old school on this problem's butt:
def deepReverse(L):
"""Input a list tot output a reversed form of it"""
if not L:
return []
elif isinstance(L[-1], list):
return [deepReverse(L[-1])] + deepReverse(L[0:-1])
else:
return [L[-1]] + deepReverse(L[0:-1])

Categories