简体   繁体   中英

how to sort list of integers and lists in python?

Like I have this list and I tried many things but end up getting type error. Is it even possible in python?

Input = [3,1,0,4,1,[5,4,7]]

output = [0,1,1,3,4,[4,5,7]]

You can use itertools.groupby :

from itertools import groupby

def sorted_mixed(lst):
    output = []
    for k, g in groupby(lst, key=lambda x: isinstance(x, list)):
        if k: # if the group consists of lists
            output += [sorted(x) for x in g] # sort each list
        else: # if the group consists of others
            output += sorted(g)
    return output

print(sorted_mixed([3,1,0,4,1,[5,4,7]]))
# [0, 1, 1, 3, 4, [4, 5, 7]]
print(sorted_mixed([3,1,[9,4,1],4,1,[5,4]]))
# [1, 3, [1, 4, 9], 1, 4, [4, 5]]
print(sorted_mixed([[4,3],[2,1]]))
# [[3, 4], [1, 2]]

The items are sorted locally, not globally. For a different behavior more information should be given.

from itertools import groupby, chain

def local_ordering(lst): # depends on groupby & chain
    return list(chain.from_iterable([sorted(next(grp))] if gr_type is list else sorted(grp) for gr_type, grp in groupby(lst, key=type)))


def global_values_local_lists_ordering(lst): # depends on itertools.groupy
    # global for values, local for lists
    grps = {}
    only_numbers = []
    # group by type
    for i, (gr_type, grp) in enumerate(groupby(lst, key=type)):
        if gr_type == list:
            # sort nested list
            grps[i] = sorted(next(grp))
        else:
            # add grp size
            g = list(grp)
            grps[i] = len(g)
            only_numbers.extend(g)
    # in place sort
    only_numbers.sort()

    # final list
    out = []
    for v in grps.values():
        if isinstance(v, list):
            out.append(v)
        else:
            # iterate over group of numbers
            for i in range(v):
                out.append(only_numbers.pop(0))
    return out


def global_ordering(lst): # no imports needed
    # flat the list
    flat_list = []
    lists_info = {}
    for i, term in enumerate(lst):
        if isinstance(term, list):
            lists_info[i] = len(term)
            flat_list.extend(term)
        else:
            flat_list.append(term)
    # in-place sort
    flat_list.sort()

    # regrouping
    out = []
    index = 0
    while flat_list:
        if index in lists_info:
            step = lists_info.pop(index)
            out.append([flat_list.pop(0) for _ in range(step)])
        else:
            out.append(flat_list.pop(0))
        index += 1

    return out

Tests and (order) ambiguities:

Case from the question: every implementation has the same output

a = [3,1,0,4,1,[5,4,7]]
print(a)
print()
print(local_ordering(a))
print(global_values_local_lists_ordering(a))
print(global_ordering(a))

Output

[3, 1, 0, 4, 1, [5, 4, 7]]

[0, 1, 1, 3, 4, [4, 5, 7]]
[0, 1, 1, 3, 4, [4, 5, 7]]
[0, 1, 1, 3, 4, [4, 5, 7]]

With a different list with more sublists: each implementation behave differently, hence "order ambiguity"

a = [3,1, [9, 4, 1],4,1,[5,4]]
print(a)
print()
print(local_ordering(a))
print(global_values_local_lists_ordering(a))
print(global_ordering(a))

Output

[3, 1, [9, 4, 1], 4, 1, [5, 4]]

[1, 3, [1, 4, 9], 1, 4, [4, 5]]
[1, 1, [1, 4, 9], 3, 4, [4, 5]]
[1, 1, [1, 3, 4], 4, 4, [5, 9]]

You could also make use of numpy arrays and masking. I assume that you want to preserve the position of the list inside the global list but order all numbers of the global list. First create a mask that differentiates list items that are numbers from list items that are list through Booleans. Then create a sorted list with the numbers, sort each inner list and place the inner list at the right position in the global list. np.dnenumerate is like enumerate for numpy arrays.

lst = [3,1,0,4,1,[5,4,7]]
import numpy as np
arr = np.array(lst)

mask = np.array([True if type(i) != list else False for i in lst])
result = sorted(arr[mask])
for idx_lst, idx_mask in np.ndenumerate(np.where(mask==False)):
    result.insert(idx_mask, sorted(arr[~mask][idx_lst[1]]))

result:

[0, 1, 1, 3, 4, [4, 5, 7]]

other example:

lst = [3,1, [9, 4, 1],4,1,[5,4]]

result:

[1, 1, [1, 4, 9], 3, 4, [4, 5]]

Hey Anshuman Sharma there are many ways to solve it, as a beginner in python I solved it like this, but there are more elegant ways with list comprehension.

Input = [3, 1, 0, 4, 1, [5, 4, 7]]
new_list = []
for value in Input:
    if type(value) != list:
        new_list.append(value)
    else:
        for element in value:
            new_list.append(element)

print(f"This is the new list: {new_list}")
new_list.sort()
print(new_list)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM