3

Let's say we have a nested list with 3 levels (D1=2,D2=3,M=2), like:

l = [[[1,a],[2,b],[3,c]], [[4,d],[5,e],[6,f]]]

I'm trying to figure out if there is any pythonic way to build 2 new nested lists with 2 levels (D1=2,D2=3), like:

l1 = [[1,2,3], [4,5,6]]
l2 = [[a,b,c], [d,e,f]]

Then we may have N levels and the lists in the deepest level contain M elements (D1,D2,D3, ..., D_N-1,M), the goal is always to build nested M lists with N-1 levels.

In other words we need to retain the hierarchy by splitting the lower level.

Other example:

l = [[[[13076, 0, 0], [806, 0, 0]], [[13076, 0, 0], [2, 0, 0]]]], [[[[2066, 0, 0], [8, 0, 0]], [[42, 0, 0], [4147, 0, 0]]]]

l1 = [[[13076,806], [13076,2]], [[2066,8],[42,4147]]]
l2 = [[[0,0], [0,0]], [[0,0], [0,0]]]
l3 = [[[0,0], [0,0]], [[0,0], [0,0]]]
kiddo
  • 135
  • 1
  • 10

4 Answers4

2

numpy syntax is convenient for this task:

import numpy as np

l = [[[1, 'a'], [2, 'b'], [3, 'c']],
     [[4, 'd'], [5, 'e'], [6, 'f']]]

a = np.array(l)

l1 = a[:, :, 0].astype(int).tolist()

# [[1, 2, 3], [4, 5, 6]]

l2 = a[:, :, 1].tolist()

# [['a', 'b', 'c'], ['d', 'e', 'f']]
jpp
  • 159,742
  • 34
  • 281
  • 339
2

You simply do :

l1=[[i[0] for i in j] for j in l]
l2=[[i[1] for i in j] for j in l]
Dadep
  • 2,796
  • 5
  • 27
  • 40
  • Any solution that does not imply knowledge of nested depth? – kiddo Mar 12 '18 at 11:34
  • @kiddo it doesn't seem so easy without knowing it, but may have a look to adapt from : https://stackoverflow.com/questions/6039103/counting-depth-or-the-deepest-level-a-nested-list-goes-to – Dadep Mar 12 '18 at 11:56
0

Use map within map

l = [[[1,"a"],[2,"b"],[3,"c"]], [[4,"d"],[5,"e"],[6,"f"]]]
l1 = list(map(lambda x: list(map(lambda y: y[0], x)), l))
l2 = list(map(lambda x: list(map(lambda y: y[1], x)), l))
0

For arbitrary depth, you can use recursion:

def transpose(s):
  return list(map(list, zip(*[list(map(list, zip(*i))) if all(all(not isinstance(c, list) for c in h) for h in i) else transpose(i) for i in s])))

l = [[[[13076, 0, 0], [806, 0, 0]], [[13076, 0, 0], [2, 0, 0]]]], [[[[2066, 0, 0], [8, 0, 0]], [[42, 0, 0], [4147, 0, 0]]]]
l2 = [[[1,'a'],[2,'b'],[3,'c']], [[4,'d'],[5,'e'],[6,'f']]] 
new_data1 = {'l{}'.format(i):a for i, a in enumerate(transpose(l), start=1)}
new_data2 = {'l{}'.format(i):a for i, a in enumerate(transpose(l2), start=1)}

Output:

{'l2': [[[[0, 0], [0, 0]]], [[[0, 0], [0, 0]]]], 'l3': [[[[0, 0], [0, 0]]], [[[0, 0], [0, 0]]]], 'l1': [[[[13076, 806], [13076, 2]]], [[[2066, 8], [42, 4147]]]]}

{'l2': [['a', 'b', 'c'], ['d', 'e', 'f']], 'l1': [[1, 2, 3], [4, 5, 6]]}
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • Thanx, but here you imply types of the inner list's elements and the outputs are also mixed... – kiddo Mar 12 '18 at 11:44
  • @kiddo `type(c) in [int, str]` implies that the inner elements can be either ints or strings. Can you post a sample of what your deeper nested data looks like? – Ajax1234 Mar 12 '18 at 11:46
  • currently there are only integers, I'm just wondering if this could be extended to any type... Is it possible to fix the output as it is in the question? These lists are actually represent input features that need to be fed to a neural net, which means that we need to feed three parallel lists in order to embed these different features that refer to the same datapoint... – kiddo Mar 12 '18 at 11:58
  • @kiddo Please see my recent edit. I changed the solution to support values of arbitrary types. – Ajax1234 Mar 12 '18 at 12:06
  • Great, can we have the output in this form? l1 = [[1,2,3], [4,5,6]] l2 = [[a,b,c], [d,e,f]] – kiddo Mar 12 '18 at 12:07
  • Please see the new list (l) in the bottom of the question, the first step of transpose works fine, but then if I call l1, l2, l3 = map(list, zip(*transpose(l))), I get "ValueError: not enough values to unpack (expected 3, got 1)". I think now we imply the number of output lists :) – kiddo Mar 12 '18 at 12:35