expanding arbitrary number of sublists within a list - python

I am trying to expand sublists within a list. I wrote it for one layer of sublists within the list. Is there a better way to code this so to scale for arbitrary number of nested lists? See example as follows:
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
def expand(x):
# expands a list of lists with no further sublists
a = []
for i in x:
# could also here do a += i and avoid the second for loop
for j in i:
a.append(j)
return a
print expand(c)
Returns the desired [1, 2, 3, 4, 5, 6]
To further clarify, I am wondering how to better scale for
`e = [c, a, b]' and further nested iterations.

c = [[1, 2, 3], [4, 5, 6]]
# first method
res = [x for lst in c for x in lst]
# second method
from itertools import chain
res = list(chain(*c))
Edit: he wants iteratively nested lists!
c = [[[1], [2, 3]], [4, 5], [[6, 7, 8], 9]]
def expand(lst):
try:
for a in lst:
for b in expand(a):
yield b
except TypeError:
yield lst
res = list(expand(c)) # => [1, 2, 3, 4, 5, 6, 7, 8, 9]

Use Recursion:
def flat_list(l):
for a in l:
if isinstance(a, list):
for x in flat_list(a):
yield x
else:
yield a
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
e = [c, a, b]
print list(flat_list(c))
print list(flat_list(e))
the output is:
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]

One solution:
def flatten(ls):
result = []
stack = [ls]
while stack:
if isinstance(stack[-1], list):
try: stack.append(stack[-1].pop(0))
except IndexError: stack.pop() # remove now-empty sublist
else:
result.append(stack.pop())
return result
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
e = [c, a, b]
print flatten(e)
Output:
[1, 2, 3, 4, 5, 6]
Or :
Using sum:
>>> e
[[[1, 2, 3], [4, 5, 6]], [1, 2, 3], [4, 5, 6]]
>>> sum(e[0], [])
[1, 2, 3, 4, 5, 6]
Using reduce:
>>> reduce(lambda x,y: x+y, e[0])
[1, 2, 3, 4, 5, 6]
>>>

Related

Intersection needed for multiple lists without knowing the content of the list

I want to take multiple lists and know the values that appaer in these lists with the possibility of one or more of the lists being empty.
CASE 1:
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
c = []
d = [2, 3, 5]
Needed output: 5
CASE 2:
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5, 3]
c = [1, 3, 8]
d = []
Needed output: 3
Order doesn't matter.
I know I can use this if there are no empty lists (source 1 / source 2)
list(set(a) & set(b) & set(c) and set(d))
The problem occurs when one of the lists is empty.
Python version: 3.8
Lets use a list comprehension with set.intersection -
The list comprehension checks if the length of the list is greater than 0 and then uses it to find an intersection using set.intersection. The * operator unpacks this list of sets, to individual sets.
Case 1:
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
c = []
d = [2, 3, 5]
l = [a,b,c,d]
l = [set(i) for i in l if len(i)>0]
set.intersection(*l)
{5}
Case 2:
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5, 3]
c = [1, 3, 8]
d = []
l = [a,b,c,d]
l = [set(i) for i in l if len(i)>0]
set.intersection(*l)
{3}
You use filter() to remove empty lists and then convert your list to set() objects using map() and do the intersection as:
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
c = []
d = [2, 3, 5]
my_list = [a, b, c, d]
my_result = set.intersection(*map(set, filter(bool, my_list)))
# where `my_result` holds the value:
# {5}

Count the number of times the positions of two lists have the same element

If you have two lists,
a = [1, 2, 3, 4, 5]
b = [1, 3, 2, 4, 7]
how can you count the number of times elements at a certain position coincide? For example 1 and 4 in the above example would have 2 cases of elements coinciding.
sum(a_ == b_ for a_, b_ in zip(a, b))
zip can give you the elements that share a position, and you can use sum to count the number of times they match:
a = [1, 2, 3, 4, 5]
b = [1, 3, 2, 4, 7]
print(sum(x == y for x, y in zip(a, b))) # 2
You can use below code and you will get positions which coincide and get sum of them as well.
a = [1, 2, 3, 4, 5]
b = [1, 3, 2, 4, 7]
print(len([i for i,val in enumerate(zip(a,b)) if val[0]==val[1]]))
to get positions you can use
print([i for i,val in enumerate(zip(a,b)) if val[0]==val[1]])
one more version:
a = [1, 2, 3, 4, 5]
b = [1, 3, 2, 4, 7]
print(sum(a[i] == b[i] for i in range(len(a))))
How about this?
# lists:
a = [1, 2, 3, 4, 5]
b = [1, 3, 2, 4, 7]
# initialize variables:
number_of_collisions = 0
# iterate over each element:
for i in range(len(a)):
if a[i] == b[i]:
number_of_collisions += 1
print(number_of_collisions)

Append many lists at once

Which is the most pythonic way and the fastest way (could be the same) to append many list together? For example, given the lists below:
a = [1, 2]
b = [3, 4]
c = [5, 6]
d = [7, 8]
we get one list:
combined = [1, 2, 3, 4, 5, 6, 7, 8]
In Python 3.5+, you can use the generic unpacking:
combined = [*a, *b, *c, *d]
or prior to Python 3.5+, you can use itertools.chain:
from itertools import chain
combined = list(chain(a, b, c, d))
I can't understand you
do you mean how to merge them?
for example
a = [1, 2]
b = [3, 4]
c = [5, 6]
d = [7, 8]
combined = a + b + c + d
so combined will be
[1, 2, 3, 4, 5, 6, 7, 8]
OR:
a = [1, 2]
b = [3, 4]
c = [5, 6]
d = [7, 8]
a.extend(b)
a.extend(c)
a.extend(d)
Now:
print(a)
Returns:
[1, 2, 3, 4, 5, 6, 7, 8]

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)

sum two lists element-by-element in python recursively [duplicate]

This question already has answers here:
Element-wise addition of 2 lists?
(17 answers)
Closed 8 years ago.
Is it possible to recursively sum two lists element by element and then return the new list?
def sumListElements(listOne, listTwo):
list = []
i = 0
while i < len(listOne):
list.append(listOne[i] + listTwo[i])
i += 1
return list
So,
a = [1, 2, 3]
b = [3, 4, 5]
Results
R = [4, 6, 8]
Here is a recursive implementation
def recursive_sum(l1, l2, idx = 0):
if idx < min(len(l1), len(l2)):
return [l1[idx] + l2[idx]] + recursive_sum(l1, l2, idx + 1)
else:
return []
print recursive_sum([1, 2, 3], [4, 5, 6])
# [5, 7, 9]
Or
def recursive_sum(l1, l2, result = None, idx = 0):
if result is None:
result = []
if idx < min(len(l1), len(l2)):
result.append(l1[idx] + l2[idx])
return recursive_sum(l1, l2, result, idx + 1)
else:
return result
Use zip() and map() here:
R = map(sum, zip(a, b))
Demo:
>>> a = [1, 2, 3]
>>> b = [3, 4, 5]
>>> map(sum, zip(a, b))
[4, 6, 8]
For Python 3 compatibility, replace map() with a list comprehension:
[sum(z) for z in zip(a, b)]
Function which takes n lists, and adds each element in an i-th index together with the others:
from itertools import izip_longest
def sum_elements(*lists):
return map(sum, izip_longest(*lists, fillvalue=0))
Showed with your data:
>>> sum_elements([1, 2, 3], [3, 4, 5])
[4, 6, 8]
Lists with uneven lengths still have a nice result:
>>> sum_elements([1, 2, 3], [3, 4, 5, 6])
[4, 6, 8, 6]
And it can take any number of lists:
>>> sum_elements([1, 2, 3], [3, 4, 5, 6], [8,9])
[12, 15, 8, 6]

Categories