Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Python sort a list of lists by occurrence and reversed order

I have the following list

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

I want to sort this list like this. So that the list sorts in an order with descending occurrence and with their reversed list. For example:

[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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

I tried:

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

which gives:

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

and

sorted(list_55,reverse=True)

gives:

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

I want a combination of these two. Is there a way to do it?

>Solution :

Try:

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

Prints:

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

A little bit more performant solution using :=:

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

For more performance a version with 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)

Prints (AMD 3700x/Python 3.9):

0.0037845000624656677
0.011112367967143655
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading