Python - How to sort multidimensional list to two-dimensional list?

后端 未结 6 493
遥遥无期
遥遥无期 2021-01-18 18:39

How i can sort multidimensional list to two-dimensional list?

Multidimensional input: [8, [6, 7, [-1], [4, [[10]]], 2], 1]

Desired two-dimension

相关标签:
6条回答
  • 2021-01-18 18:57

    You could perhaps use a defaultdict here to measure the depth of each element, along with recursion:

    from collections import defaultdict
    L = [8, [6, 7, [-1], [4, [[10]]], 2], 1]
    res = defaultdict(list)
    def myfunc(L, depth):
        for i in L:
            if isinstance(i, list):
                myfunc(i, depth+1)
            else:
                res[depth].append(i)
    
    myfunc(L, 0)
    

    The defaultdict will then look like this:

    defaultdict(<class 'list'>, {0: [8, 1], 1: [6, 7, 2], 2: [-1, 4], 4: [10]})
    

    You'll then need to translate the defaultdict back to what you want. Note that the default dict will not contain an empty list because it can't detect it (ie: [[10]] and [10] are both lists), but what it will have is a gap in the range (notice how the depth 3 is missing in the defaultdict).

    final = []
    for i in range(max(res)+1):
        if i not in res:
            final.append([])
        else:
            final.append(res[i])
    
    print(final)
    

    Very messy, I'm sure improvements could be made.

    0 讨论(0)
  • 2021-01-18 18:57

    The recursive approach taken by the other answers comes with the recursion limit imposed by Python and the overhead of two passes. A more efficient one-pass iterative approach is to implement breadth-first search using a queue of tuples of lists and associated depths:

    from collections import deque
    def flatten(lst):
        output = []
        q = deque([(lst, 0)])
        while q:
            l, depth = q.popleft()
            for i in l:
                if isinstance(i, list):
                    q.append((i, depth + 1))
                else:
                    while depth >= len(output):
                        output.append([])
                    output[-1].append(i)
        return output
    

    so that:

    flatten([8, [6, 7, [-1], [4, [[10]]], 2], 1])
    

    returns:

    [[8, 1], [6, 7, 2], [-1, 4], [], [10]]
    
    0 讨论(0)
  • 2021-01-18 19:05

    The idea is basically the same that the one in @TerryA answer, but using setdefault and checking at the end of the for loop if something of the depth was added:

    lst = [8, [6, 7, [-1], [4, [[10]]], 2], 1]
    
    
    def depths(l):
        def flatten(l, start=0, depth={}):
    
            for e in l:
                if isinstance(e, list):
                    flatten(e, start=start + 1, depth=depth)
                else:
                    depth.setdefault(start, []).append(e)
             if start not in depth:
                depth[start] = []
    
        d = {}
        flatten(l, depth=d)
    
        return [d[i] for i in range(max(d) + 1)]
    
    
    result = depths(lst)
    print(result)
    

    Output

    [[8, 1], [6, 7, 2], [-1, 4], [], [10]]
    
    0 讨论(0)
  • 2021-01-18 19:05

    You can do this by first generating a dictionary of elements at each depth (with depth as key in this dictionary and list of elements of that depth as value). The recursive function get_elements_by_depth below does this. Then all you need to do is flatten the values of that dictionary. (the function flatten_by_depth below does what you need).

    from collections import defaultdict
    
    def get_elements_by_depth(ls, cur_depth, cur_dict):
        """
            returns a dictionary with depth as key and a list of all
            elements that have that depth as value
        """
        for x in ls:
            if isinstance(x, list):
                get_elements_by_depth(x, cur_depth + 1, cur_dict)
            else:
                cur_dict[cur_depth].append(x)
        return cur_dict
    
    
    def flatten_by_depth(ls):
        """
            returns a list of lists, where the list at index i 
            contains all elements of depth i
        """
        elements_by_depth = get_elements_by_depth(ls, 0, defaultdict(list))
        max_depth = max(elements_by_depth.keys())
        # Since we're using a defaultdict, we don't have to worry about
        # missing keys in elements_by_depth
        return [
            elements_by_depth[i]
            for i in xrange(max_depth + 1)
        ]
    

    > flatten_by_depth([8, [6, 7, [-1], [4, [[10]]], 2], 1])
    [[8, 1], [6, 7, 2], [-1, 4], [], [10]]
    
    0 讨论(0)
  • 2021-01-18 19:06

    Somebody recently posted a similar question which, by the time I composed my answer, was closed as a duplicate. So I figured I'd add my answer here.

    def extract_entries(nested_list, new_list=[]):
        # Add the list of all of the items in <nested_list> that are NOT lists themselves. 
        new_list.append( [ e for e in nested_list if type(e) != list ] )
    
        # Look at entries in <nested_list> that ARE lists themselves.
        for entry in nested_list:
            if type(entry) == list:
                extract_entries(entry, new_list)
    
        return new_list
    

    Testing:

    M = [8, [6, 7, [-1], [4, [[10]]], 2], 1]
    print(extract_entries(M))
    # Returns: [[8, 1], [6, 7, 2], [-1], [4], [], [10]]
    
    0 讨论(0)
  • 2021-01-18 19:12

    My option with recursion and without any dependencies:

    lst = [8, [6, 7, [-1], [4, [[10]]], 2], 1]
    
    def flat_group(lst, deep = 0, res = None):
      if res == None: res = []
      for item in lst:
        if len(res) <= deep: res.append([])
        if not type(item) == list:
          res[deep].append((item))
        else:
          flat_group(item, deep + 1, res)
      return res
    
    
    print(flat_group(lst))
    #=> [[8, 1], [6, 7, 2], [-1, 4], [], [10]]
    


    To show How it works, I split the method in two:

    def flat(lst, deep = 0, res = []):
      for item in lst:
        if not type(item) == list:
          res.append((deep, item))
        else:
          flat(item, deep + 1, res)
      return res
    
    def group(lst):
      flatten = flat(lst)
      max_n = max(flatten)[0]
      res = [[] for _ in range(0,max_n+1)]
      for deep, item in flatten:
        res[deep].append(item)
      return res
    
    print(group(lst))
    #=> [[8, 1], [6, 7, 2], [-1, 4], [], [10]]
    

    flat(lst) is a recursive method that builds a flat list of tuples where each tuple contains the value and the deep inside the original list. So the call flat(lst) returns:

    # [(0, 8), (1, 6), (1, 7), (2, -1), (2, 4), (4, 10), (1, 2), (0, 1)]
    

    Then group(lst) builds a list of n+1 empty sub-list, where n is the maximum depth, it iterates over the result of flat(lst) and append each element by index to the proper sub-list.

    The flat_group(lst) does almost the same.

    0 讨论(0)
提交回复
热议问题