Python 3: Reverse consecutive runs in a sorted list?

It's a question of expansion. What is the most Pythonic way to identify consecutive duplicates in a list? .

Suppose you have a list of tuples:

my_list = [(1,4), (2,3), (3,2), (4,4), (5,2)]

and you sort it by each last value of the tuple:

my_list = sorted(my_list, key=lambda tuple: tuple[1])
# [(3,2), (5,2), (2,3), (1,4), (4,4)]

then we have two consecutive runs (depending on the last value in each tuple), namely [(3,2), (5,2)]and [(1,4), (4,4)].

What is the pythonic way to cancel each run (and not the tuples inside) e.g.

reverse_runs(my_list)
# [(5,2), (3,2), (2,3), (4,4), (1,4)]

Can this be done in the generator?

UPDATE

I realized that perhaps the list of examples is not clear. Therefore, consider instead:

my_list = [(1,"A"), (2,"B"), (5,"C"), (4,"C"), (3,"C"), (6,"A"),(7,"A"), (8,"D")]

If the ideal output of the reverse_runswill

[(7,"A"), (6,"A"), (1,"A"), (2,"B"), (3,"C"), (4,"C"), (5,"C"), (8,"D")]

, "run", TimSort, Python, - ( ) .

, , , , , .

, :

sorted(my_list,key=lambda t: t[1])

:

[(1, 'A'), (6, 'A'), (7, 'A'), (2, 'B'), (5, 'C'), (4, 'C'), (3, 'C'), (8, 'D')]

"C" (.. (5, 'C'), (4, 'C'), (3, 'C')) .

, reverse_runs:

1.)

2.), ,

, ( ) .

, :

1.) sorted(my_list, key=lambda tuple: tuple[1])

2.) , (i + 1) (i).

3.)

4.) , ,

+4
2

2 . - reversed . - :

pass1 = sorted(my_list, key=itemgetter(0), reverse=True)
result = sorted(pass1, key=itemgetter(1))

, , python stable.

, . "" , :

result = sorted(my_list, key=lambda t: (t[1], -t[0]))

:

from operator import itemgetter
from itertools import chain, groupby
my_list = [(1,"A"), (2,"B"), (5,"C"), (4,"C"), (3,"C"), (6,"A"),(7,"A"), (8,"D")]

pass1 = sorted(my_list, key=itemgetter(1))
result = list(chain.from_iterable(reversed(list(g)) for k, g in groupby(pass1, key=itemgetter(1))))
print(result)

:

chain.from_iterable(reversed(list(g)) for k, g in groupby(pass1, key=itemgetter(1)))

, ...

groupby(pass1, key=itemgetter(1)). groupby 2-. (k) - "" - , , itemgetter(1). , . (g - "group" ) , , "" . , , , . . , , . reversed(list(g)). , , chain.from_iterable.

, (, "" ). , , . , , :

from collections import defaultdict, deque
from itertools import chain

my_list = [(1,"A"), (2,"B"), (5,"C"), (4,"C"), (3,"C"), (6,"A"),(7,"A"), (8,"D")]

bins = defaultdict(deque)
for t in my_list:
    bins[t[1]].appendleft(t)

print(list(chain.from_iterable(bins[key] for key in sorted(bins))))

, , , . TimSort - , , , , ( , ...). , ( , TimSort MergeSort), .

+2

, .

my_list = [(1,4), (2,3), (3,2), (4,4), (5,2)]
my_list = sorted(my_list, key=lambda tuple: (tuple[1], -tuple[0]))

print(my_list)

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

. , , :

from itertools import groupby
from operator import itemgetter


def reverse_runs(l):
    sorted_list = sorted(l, key=itemgetter(1))
    reversed_groups = (reversed(list(g)) for _, g in groupby(sorted_list, key=itemgetter(1)))
    reversed_runs = [e for sublist in reversed_groups for e in sublist]

    return reversed_runs


if __name__ == '__main__':
    print(reverse_runs([(1, 4), (2, 3), (3, 2), (4, 4), (5, 2)]))
    print(reverse_runs([(1, "A"), (2, "B"), (5, "C"), (4, "C"), (3, "C"), (6, "A"), (7, "A"), (8, "D")]))

[(5, 2), (3, 2), (2, 3), (4, 4), (1, 4)]
[(7, 'A'), (6, 'A'), (1, 'A'), (2, 'B'), (3, 'C'), (4, 'C'), (5, 'C'), (8, 'D')]

:

from itertools import groupby
from operator import itemgetter


def reverse_runs(l):
    sorted_list = sorted(l, key=itemgetter(1))
    reversed_groups = (reversed(list(g)) for _, g in groupby(sorted_list, key=itemgetter(1)))

    for group in reversed_groups:
        yield from group


if __name__ == '__main__':
    print(list(reverse_runs([(1, 4), (2, 3), (3, 2), (4, 4), (5, 2)])))
    print(list(reverse_runs([(1, "A"), (2, "B"), (5, "C"), (4, "C"), (3, "C"), (6, "A"), (7, "A"), (8, "D")])))
+4

Source: https://habr.com/ru/post/1668016/


All Articles