如何对列表和整数列表进行大范围排序?

How to sort liberally-deep list of lists and integers?

提问人:Piotr Wasilewicz 提问时间:10/7/2022 最后编辑:Piotr Wasilewicz 更新时间:10/8/2022 访问量:92

问:

假设我有一个这样的列表:

[[5, [2, 1], 3], [3, [8, 7], [2, 1, 3], 2], [[3, 2, 1], 3, -1]]

(每个列表可以以任何顺序存储未指定数量的整数和列表)。 排序规则:

  • 整数(如果有)应位于任何列表之前
  • 整数按正常排序(从小值到高值)
  • 当第一个元素较低时,列表比另一个元素“小”,如果相同,则考虑第二个元素、第三个元素,依此类推。
  • 如果列表的值与另一个列表的值相同但更少,则该列表较小。[1, 2] < [1, 2, 3]

所以最终结果应该是:

[[-1, 3, [1, 2, 3]], [2, 3, [1, 2, 3], [7, 8]], [3, 5, [1, 2]], ]

如何实现这种排序?我尝试将递归函数作为键传递,但大多以 TypeError(不支持 和 )结尾。sortsorted<intlist

另一个例子:

[1, 4, 3, [[5, 7, 1, 2], 2, 5, 10, 2], 8, [2, 5, [5, 3, 3]], [2, 5, 10, 2, [1, 2, 5]]]

排序后:

[1, 3, 4, 8, [2, 2, 5, 10, [1, 2, 5]], [2, 2, 5, 10, [1, 2, 5, 7]], [2, 5, [3, 3, 5]]]
Python 对嵌套列表 进行排序

评论

0赞 MYousefi 10/7/2022
因为第一个是较短的大小列表,第二个是较长的大小列表。基本上,列表长度的优先级高于列表值。34

答:

1赞 Marek 10/7/2022 #1

快速草稿:

def big_brain_sort(li: list) -> list:
    list_with_int = []
    list_with_list = []
    for el in li:
        if isinstance(el, int):
            list_with_int.append(el)
        elif isinstance(el, list):
            list_with_list.append(big_brain_sort(el))
    sorted_list_int = sorted(list_with_int)
    for lista in sorted(list_with_list, key=lambda x: (big_brain_sort(x), len(x))):
        sorted_list_int.append(lista)
    return sorted_list_int

评论

0赞 Piotr Wasilewicz 10/7/2022
欢迎使用 stackoverflow。似乎代码可以满足我的需要。带有元组的不错“技巧”。lambda
0赞 Piotr Wasilewicz 10/7/2022
但是,您应该修复缩进。
0赞 Kelly Bundy 10/7/2022
@PiotrWasilewicz 我不认为 lambda 很好。如果我没记错的话,该键功能除了浪费时间(可能很多)之外没有任何效果。简化版
1赞 Kelly Bundy 10/7/2022
@PiotrWasilewicz 我并不是说它不起作用。我是说它做了毫无意义的重复工作。
1赞 Piotr Wasilewicz 10/7/2022
它不起作用[[1, 2], [1, [2]]]
2赞 Kelly Bundy 10/7/2022 #2

正确、安全、高效地比较同级结构(即,在同一列表中深度嵌套的值)的一种方法是装饰所有内容并保持装饰状态,直到所有排序完成。然后在最后取消所有东西。这不会修改给定的结构,而是构建一个排序的新结构:

def deepsorted(x):
    def decosorted(x):
        if isinstance(x, int):
            return 0, x
        return 1, sorted(map(decosorted, x))
    def undecorated(x):
        islist, x = x
        if islist:
            return list(map(undecorated, x))
        return x
    return undecorated(decosorted(x))

另一种方法是不依赖自然比较,而是使用旧式函数。这就地排序:cmp

from functools import cmp_to_key

def deepsort(x):
    def cmp(a, b):
        if isinstance(a, int):
            if isinstance(b, int):
                return a - b
            return -1
        if isinstance(b, int):
            return 1
        diffs = filter(None, map(cmp, a, b))
        return next(diffs, len(a) - len(b))
    key = cmp_to_key(cmp)
    def sort(x):
        if isinstance(x, list):
            for y in x:
                sort(y)
            x.sort(key=key)
    sort(x)

测试代码(在线试用!

from copy import deepcopy

tests = [
    ([[5, [2, 1], 3], [3, [8, 7], [2, 1, 3], 2], [[3, 2, 1], 3, -1]],
     [[-1, 3, [1, 2, 3]], [2, 3, [1, 2, 3], [7, 8]], [3, 5, [1, 2]], ]),

    ([1, 4, 3, [[5, 7, 1, 2], 2, 5, 10, 2], 8, [2, 5, [5, 3, 3]], [2, 5, 10, 2, [1, 2, 5]]],
     [1, 3, 4, 8, [2, 2, 5, 10, [1, 2, 5]], [2, 2, 5, 10, [1, 2, 5, 7]], [2, 5, [3, 3, 5]]]),

    ([[1, 2], [1, [2]]],
     [[1, 2], [1, [2]]]),

    ([[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]],
     [[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]),

    ([[[1, 2]], [[1, [2]]]],
     [[[1, 2]], [[1, [2]]]]),

    ([[[1, [2]]], [[1, 2]]],
     [[[1, 2]], [[1, [2]]]]),

    ([[1, 3], [1, 2]],
     [[1, 2], [1, 3]]),
]

for given, wanted in tests:
    copy = deepcopy(given)
    deepsort(copy)
    print(deepsorted(given) == wanted,
          copy == wanted)

评论

0赞 Piotr Wasilewicz 10/7/2022
哇,这很短(而且可能有效)。也检查了其他情况。
0赞 Piotr Wasilewicz 10/7/2022
我正在调试这个。现在将接受马雷克版本,如果你有东西就写。
0赞 Piotr Wasilewicz 10/7/2022
在这种情况下,马雷克的解决方案也被打破了。
0赞 Kelly Bundy 10/8/2022
@PiotrWasilewicz我用两种我认为行之有效的方式代替了它。这出乎意料地棘手。
0赞 Piotr Wasilewicz 10/8/2022
是的,我想“好吧,我需要这些关系始终以相同的顺序排列,有嵌套的 ID......订购它应该很容易“,那么公司里没有人知道如何去做:)检查了我所有的案例(不多)。似乎工作得很好。