How to split a nested list into multiple nested lists? - python

I have a nested list shaped like
mylist = [[a, b, c, d], [e, f, g, h], [i, j, k, l]]
And i need to split the nested lists so that every two items are grouped together like this:
Nested_list = [[[a, b], [c, d], [[e, f], [g, h]], [[i, j], [k, l]]
I tried splitting them by them by usinga for loop that appended them but this doesn't work.

mylist = [['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']]
nested_list = [ [i[:2], i[2:]] for i in mylist ]
print(nested_list)
Output:
[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']], [['i', 'j'], ['k', 'l']]]

mylist = [['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j', 'k', 'l']]
Nested_list = []
for x in mylist:
Nested_list.append(x[:2])
Nested_list.append(x[2:])
print(Nested_list)
Output: [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h'], ['i', 'j'], ['k', 'l']]

import numpy as np
Nested_list = np.array(mylist).reshape(-1,2,2)
output:
array([[['a', 'b'],
['c', 'd']],
[['e', 'f'],
['g', 'h']],
[['i', 'j'],
['k', 'l']]], dtype='<U1')

from itertools import *
my_list = chain.from_iterable(my_list)
def grouper(inputs, n):
iters = [iter(inputs)] * n
return zip_longest(*iters)
print(list(grouper(my_list, 2)))

Related

Python aggregate lists that share a common item

I'm looking for a function to aggregate lists that have a common item. The specific example I had in mind was the following case:
inputs = [['a','b'], ['a','c'], ['b','d'], ['e','f'], ['g','h'], ['i','k'], ['k','l']]
aggregated_output = [['a','b','c','d'],['e','f'],['g','h'],['i','k','l']]
as you can see, all the lists that share a common item have been bunched together. The order of the lists or the items in the lists in the output does not matter.
Maybe Brute-Force Solutions help you:
inputs = [['a','b'], ['a','c'], ['b','d'], ['e','f'], ['g','h'], ['i','k'], ['k','l']]
res = []
for arr in inputs:
flaq = False
for r in res:
for a in arr:
if a in r:
r += [a for a in arr if not a in r]
flaq = True
break
if not flaq:
res.append(arr)
print(res)
Output:
[['a', 'b', 'c', 'd'], ['e', 'f'], ['g', 'h'], ['i', 'k', 'l']]
You could use connected_components from the networkx package:
>>> import networkx as nx
>>> edges = [['a', 'b'], ['a', 'c'], ['b', 'd'], ['e', 'f'], ['g', 'h'], ['i', 'k'], ['k', 'l']]
>>> graph = nx.Graph()
>>> graph.add_edges_from(edges)
>>> [list(c) for c in nx.connected_components(graph)]
[['a', 'c', 'd', 'b'], ['f', 'e'], ['h', 'g'], ['k', 'i', 'l']]

Sort multi level nested list in groups and by level

I have a list:
['A', 'B', 'C', ['D', ['E', 'F'], 'G'], 'H']
and I want to turn this into:
[['E', 'F'], ['D', 'G'], ['A', 'B', 'C', 'H']]
So basically I want the sublist on the deepest level of the list to come first in the new list and then counting down the level the remaining sublists.
This should work with any nested list.
If there are two sublists on the same level, then it doesn't really matter which one comes first.
['A', 'B', 'C', ['D', ['E', 'F'], 'G'], ['H', 'I', 'J']]
[['E', 'F'], ['D', 'G'], ['H', 'I', 'J'], ['A', 'B', 'C', 'H']] #this is fine
[['E', 'F'], ['H', 'I', 'J'], ['D', 'G'], ['A', 'B', 'C', 'H']] #this too
I thought of first using a function to determine on what level the deepest sublist is, but then again I don't know how to access items in a list based on their level or if that's even possible.
Been tinkering around this for far too long now and I think my head just gave up, hope someone can assist me with this problem!
You can use a recursive generator function:
def sort_depth(d, c = 0):
r = {0:[], 1:[]}
for i in d:
r[not isinstance(i, list)].append(i)
yield from [i for j in r[0] for i in sort_depth(j, c+1)]
yield (c, r[1])
def result(d):
return [b for _, b in sorted(sort_depth(d), key=lambda x:x[0], reverse=True) if b]
print(result(['A', 'B', 'C', ['D', ['E', 'F'], 'G'], 'H']))
print(result(['A', 'B', 'C', ['D', ['E', 'F'], 'G'], ['H', 'I', 'J']]))
print(result([[1, [2]], [3, [4]]]))
Output:
[['E', 'F'], ['D', 'G'], ['A', 'B', 'C', 'H']]
[['E', 'F'], ['D', 'G'], ['H', 'I', 'J'], ['A', 'B', 'C']]
[[2], [4], [1], [3]]
Here is a relatively straight-forward solution:
def sort_depth(d):
def dlists(obj, dep=0):
for x in filter(list.__instancecheck__, obj):
yield from dlists(x, dep-1)
yield [x for x in obj if not isinstance(x, list)], dep
return [x for x, y in sorted(dlists(d), key=lambda p: p[1])]
>>> [*sort_depth([[1, [2]], [3, [4]]])]
[[2], [4], [1], [3], []]
>>> [*sort_depth(['A', 'B', 'C', ['D', ['E', 'F'], 'G'], 'H'])]
[['E', 'F'], ['D', 'G'], ['A', 'B', 'C', 'H']]
The approach:
Collect all the sublists and annotate them with their (negative) nesting level, e.g. (['E', 'F'], -2)
Sort them by their nesting level
Extract the lists back from the sorted data

Getting all the permutations of a nested elements in a list- python 2

So its not the permutations Im having trouble with, rather that the outcome lists are not equivalent to the original list I started with.
The list is this,
B=[[m, b], [c, g], [d, f]]
and the code Ive used to get all the permutation is this, along with the outcome,
C=list(itr.permutations(B))
C
[([m, b], [c, g], [d, f]),
([m, b], [d, f], [c, g]),
([c, g], [m, b], [d, f]),
([c, g], [d, f], [m, b]),
([d, f], [m, b], [c, g]),
([d, f], [c, g], [m, b])]
Is there any way to not have the inner lists in parentheses, rather instead in square bracket, because as of now C[0] is not the same as B, when in fact they should be equal.
C[0]==B
False
Ive defined the letters (m, b, d, etc) as symbols in sympy rather then as strings.
Any advice is appreciated.
You can use map() to turn the tuples into lists:
>>> import itertools as itr
>>> B=[[m, b], [c, g], [d, f]]
>>> C = map(list, itr.permutations(B))
>>> C
[[['m', 'b'], ['c', 'g'], ['d', 'f']], [['m', 'b'], ['d', 'f'], ['c', 'g']], [['c', 'g'], ['m', 'b'], ['d', 'f']], [['c', 'g'], ['d', 'f'], ['m', 'b']], [['d', 'f'], ['m', 'b'], ['c', 'g']], [['d', 'f'], ['c', 'g'], ['m', 'b']]]
>>> C[0] == B
True
Also, you can use itertools imap() if you want to keep it as an iterator.
Just use C[0][0] == B[0]
>>> print(C)
[(['m', 'b'], ['c', 'g'], ['d', 'f']), (['m', 'b'], ['d', 'f'], ['c', 'g']), (['c', 'g'], ['m', 'b'], ['d', 'f']), (['c', 'g'], ['d', 'f'], ['m', 'b']), (['d', 'f'], ['m', 'b'], ['c', 'g']), (['d', 'f'], ['c', 'g'], ['m', 'b'])]
>>> print(B)
[['m', 'b'], ['c', 'g'], ['d', 'f']]
>>> C[0][0]
['m', 'b']
>>> B[0]
['m', 'b']
>>> C[0][0] == B[0]
True
>>> C[0][1] == B[1]
True

How to create sub-lists with 3 elements, but if a sub-list gets a single element then instead create two with 2 elements?

Follows an example to clarify the 2-elements sub-lists use case:
If a list has 10 elements [A, B, C, D, E, F, G, H, I, J] I would like to get 4 sub-lists: [[A, B, C], [D, E, F], [G, H], [I, J]].
Thanks in advance.
Here's a solution using an iterator:
L = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
N = len(L)
I = iter(L)
[[next(I) for _ in range(size)] for size in [3]*(N//3-1) + ([3] if (N%3)==0 else ([2,2] if (N%3)==1 else [3,2]))]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H'], ['I', 'J']]
I would do a function:
def partition(a):
arr = np.array(a)
n = len(arr) # assume that n>=3
r = n % 3
if r == 0:
return list(arr.reshape(-1, 3))
if r == 1:
return list(arr[:-4].reshape(-1,3)) + list(arr[-4:].reshape(-1,2))
# r == 2
return list(arr[:-2].reshape(-1,3)) + [arr[-2:]]
Test:
partition(list('ABCDEFGHIJ'))
# [array(['A', 'B', 'C'], dtype='<U1'), array(['D', 'E', 'F'], dtype='<U1'),
# array(['G', 'H'], dtype='<U1'), array(['I', 'J'], dtype='<U1')]
partition(list('ABCDEFGHI'))
# [array(['A', 'B', 'C'], dtype='<U1'), array(['D', 'E', 'F'], dtype='<U1'),
# array(['G', 'H', 'I'], dtype='<U1')]
partition(list('ABCDEFGH'))
# [array(['A', 'B', 'C'], dtype='<U1'), array(['D', 'E', 'F'], dtype='<U1'),
# array(['G', 'H'], dtype='<U1')]
How about:
l = list('ABCDEFGHIJ')
n = len(l)
res = [ l[(i if i < n-1 else i-1) : (i+3 if i < n-4 or i == n-3 else i+2)] for i in range(0,n,3)]
print(res)
This would give following outputs:
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H'], ['I', 'J']]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I'], ['J', 'K']]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I'], ['J', 'K', 'L']]
[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I'], ['J', 'K'], ['L', 'M']]

Duplicate every value in array as a new array

I have an numpy ndarray input like this
[[T, T, T, F],
[F, F, T, F]]
and I want to duplicate every value as a new array, so the output would be
[[[T,T], [T,T], [T,T], [F,F]]
[[F,F], [F,F], [T,T], [F,F]]]
How can I do this? Thank you in advance
One way would be using np.dstack to replicate the array along the third axis:
np.dstack([a, a])
array([[['T', 'T'],
['T', 'T'],
['T', 'T'],
['F', 'F']],
[['F', 'F'],
['F', 'F'],
['T', 'T'],
['F', 'F']]], dtype='<U1')
Setup:
T = 'T'
F = 'F'
a = np.array([[T, T, T, F],
[F, F, T, F] ])
you can just use list comprehension:
data =[['T', 'T', 'T', 'F'],
['F', 'F', 'T', 'F'] ]
d = [[[i]*2 for i in j] for j in data]
print (d)
output:
[[['T', 'T'], ['T', 'T'], ['T', 'T'], ['F', 'F']], [['F', 'F'], ['F', 'F'], ['T', 'T'], ['F', 'F']]]

Categories