Skip to main content
added 630 characters in body
Source Link
clutton
  • 819
  • 8
  • 13

When sorting by multiple keys, I am intendingneed the second key to use "alternate_sort"alternate between standard and reverse sorting. This is to minimize the change in the second key. For example, if I have a list of dictionaries, I want the first sort order(group key) to be sorted and then the second sort (sort key) to alternate. This should produce a sort like this:

[{'group': 'a', 'sort': 1},
 {'group': 'a', 'sort': 2},
 {'group': 'a', 'sort': 2},
 {'group': 'b', 'sort': 2},
 {'group': 'b', 'sort': 1},
 {'group': 'b', 'sort': 1},
 {'group': 'c', 'sort': 1},
 {'group': 'c', 'sort': 1},
 {'group': 'c', 'sort': 2}]

That limits the change in the "sort key" when there are "group key"field called "sort" as it alternates each time as the "group" changes. I

I have looked around and did not see a standard way to accomplish this without rolling my own. I think the code is fairly straight forward but curious if I might be missing something or an easier/faster way.

I am intending to use "alternate_sort" to change sort order in the "sort key" when there are "group key" changes. I have looked around and did not see a standard way to accomplish this without rolling my own. I think the code is fairly straight forward but curious if I might be missing something or an easier/faster way.

When sorting by multiple keys, I need the second key to alternate between standard and reverse sorting. This is to minimize the change in the second key. For example, if I have a list of dictionaries, I want the first sort (group key) to be sorted and then the second sort (sort key) to alternate. This should produce a sort like this:

[{'group': 'a', 'sort': 1},
 {'group': 'a', 'sort': 2},
 {'group': 'a', 'sort': 2},
 {'group': 'b', 'sort': 2},
 {'group': 'b', 'sort': 1},
 {'group': 'b', 'sort': 1},
 {'group': 'c', 'sort': 1},
 {'group': 'c', 'sort': 1},
 {'group': 'c', 'sort': 2}]

That limits the change in the field called "sort" as it alternates each time as the "group" changes.

I have looked around and did not see a standard way to accomplish this without rolling my own. I think the code is fairly straight forward but curious if I might be missing something or an easier/faster way.

Source Link
clutton
  • 819
  • 8
  • 13

Alternating sort order within a sorted group

I am intending to use "alternate_sort" to change sort order in the "sort key" when there are "group key" changes. I have looked around and did not see a standard way to accomplish this without rolling my own. I think the code is fairly straight forward but curious if I might be missing something or an easier/faster way.

Any comments would be appreciated.

#!/usr/bin/env python3
""" Misc sort routines """
from operator import itemgetter
import pprint


def alternate_sort(data, group_key, sort_key,
        group_reverse=False, sort_reverse=False):
    """ Sort data within groups while alternating asc/desc on sort key. """
    partitions = []     # Tuples of start/end indexes per group
    last_key = None     # Remember when groups change
    group_start = 0     # Remember start index of group
    final_sort = []     # The final sorted listing

    # Make sure the data is sorted by group
    data = sorted(data, key=itemgetter(group_key), reverse=group_reverse)

    # Gather the group partitions
    for i, g in enumerate(data):

        # When the group changes
        if last_key != g[group_key]:

            # End the previous group partition if there is one
            if i > 0:
                partitions.append((group_start, i))

            # Start a new group partition
            group_start = i
            last_key = g[group_key]

    # Close the last group partition
    partitions.append((group_start, len(data)))

    # Go through the partitions, alternate the sort each time using sort key.
    for i, p in enumerate(partitions):
        part = data[p[0]: p[1]]
        if i % 2 == 0:
            final_sort += sorted(
                    part, key=itemgetter(sort_key), reverse=sort_reverse)
        else:
            final_sort += sorted(
                    part, key=itemgetter(sort_key), reverse=not sort_reverse)

    return final_sort


if __name__ == "__main__":
    unsorted_data = [
            {"group": "a", "sort" : 1},
            {"group": "a", "sort" : 2},
            {"group": "b", "sort" : 2},
            {"group": "b", "sort" : 1},
            {"group": "c", "sort" : 1},
            {"group": "a", "sort" : 2},
            {"group": "c", "sort" : 2},
            {"group": "b", "sort" : 1},
            {"group": "c", "sort" : 1}
    ]

    sorted_data = alternate_sort(unsorted_data, "group", "sort",
            group_reverse=True, sort_reverse=True)
    pprint.pprint(sorted_data)

    sorted_data = alternate_sort(unsorted_data, "group", "sort")
    pprint.pprint(sorted_data)