簡體   English   中英

Python 按出現和倒序對列表進行排序

[英]Python sort a list of lists by occurrence and reversed order

我有以下列表

list_55 = [[1,2],[2,1],[3,4],[5,6],[4,3],[1,2],[1,2],[6,5],[6,5]]

我想像這樣對這個列表進行排序。 以便列表按降序排列和倒序排列。 例如:

[1,2],[1,2],[1,2] followed by [2,1]
[6,5],[6,5] followed by [5,6]
[4,3] followed by [3,4] The order of this last one doesn't matter. 

output:

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

我試過了:

sorted(list_55, key=list_55.count, reverse=True)

這使:

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

sorted(list_55,reverse=True)

給出:

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

我想要這兩者的結合。 有沒有辦法做到這一點?

嘗試:

print(
    sorted(
        list_55,
        key=lambda l: (
            list_55.count(l) + list_55.count(l[::-1]),
            list_55.count(l),
        ),
        reverse=True,
    )
)

印刷:

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

使用:=的更高效的解決方案:

print(
    sorted(
        list_55,
        key=lambda l: (
            (cnt := list_55.count(l)) + list_55.count(l[::-1]),
            cnt,
        ),
        reverse=True,
    )
)

為了獲得更高的性能,使用functools.lru_cache的版本:

from timeit import timeit
from functools import lru_cache
from collections import defaultdict, Counter

list_55 = [
    [1, 2],
    [2, 1],
    [3, 4],
    [5, 6],
    [4, 3],
    [1, 2],
    [1, 2],
    [6, 5],
    [6, 5],
]


def fn1(lst):
    @lru_cache(maxsize=None)
    def key_fn(l):
        cnt = lst.count(l)
        return cnt + lst.count(l[::-1]), cnt

    lst[:] = map(tuple, lst)

    return sorted(
        lst,
        key=key_fn,
        reverse=True,
    )


def fn2(l):
    dct = defaultdict(Counter)
    for lst in l:
        dct[frozenset(lst)].update({tuple(lst): 1})

    # counters_sorted = sorted(
    #     dct.values(), key=lambda c: c.total(), reverse=True
    # )
    counters_sorted = sorted(
        dct.values(), key=lambda c: sum(c.values()), reverse=True
    )  # for python < 3.10

    return [
        tup
        for counter in counters_sorted
        for tup, n in counter.most_common()
        for _ in range(n)
    ]


t1 = timeit(
    "fn1(lst)", setup="lst = list_55 * 1000", number=1, globals=globals()
)

t2 = timeit(
    "fn2(lst)", setup="lst = list_55 * 1000", number=1, globals=globals()
)

print(t1)
print(t2)

打印(AMD 3700x/Python 3.9):

0.0037845000624656677
0.011112367967143655

另一種選擇是使用collections.Counter ,我想當輸入列表很長時效率更高:

from collections import defaultdict, Counter

list_55 = [[1,2],[2,1],[3,4],[5,6],[4,3],[1,2],[1,2],[6,5],[6,5]]

dct = defaultdict(Counter)
for lst in list_55:
    dct[frozenset(lst)].update({tuple(lst): 1})

counters_sorted = sorted(dct.values(), key=lambda c: c.total(), reverse=True)
# counters_sorted = sorted(dct.values(), key=lambda c: sum(c.values()), reverse=True) # for python < 3.10

output = [tup for counter in counters_sorted
              for tup, n in counter.most_common()
              for _ in range(n)]

print(output)
# [(1, 2), (1, 2), (1, 2), (2, 1), (6, 5), (6, 5), (5, 6), (3, 4), (4, 3)]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM