Home > Mobile >  How to quick sort list of objects by different attributes using the same method?
How to quick sort list of objects by different attributes using the same method?

Time:05-18

My class is as below:

class Member:
  def __init__(self, name, zip, hire_date, birth_date):
    self.id = id
    self.name = name
    self.zip = zip
    self.hire_date = hire_date
    self.birth_date = birth_date

  def get_name(self):
    return self.name

  def get_birth_date(self):
    return self.birth_date

  def get_hire_date(self):
    return self.hire_date

  def get_zip_code(self):
    return self.zip

I have need to quick sort a list of this class object based on zip code, name, birth_date and hire_date. I can achieve these using individual sort methods. For example, quick sort by zip code:

def partition(array, begin, end):
    pivot = begin
    for i in range(begin 1, end 1):
        if array[i].get_zip_code() <= array[begin].get_zip_code():
            pivot  = 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot



def quicksort(array, begin=0, end=None):
    if end is None:
        end = len(array) - 1
    def _quicksort(array, begin, end):
        if begin >= end:
            return
        pivot = partition(array, begin, end)
        _quicksort(array, begin, pivot-1)
        _quicksort(array, pivot 1, end)
    return _quicksort(array, begin, end)

This works fine. But now how do I make the same method work on all attributes; ideally by passing an additional argument to quicksort() defining the attribute to sort on. I also wish to not call object attributes directly but by using getter methods.

This is output after sorting by zip code

Name    Zip Hire Date   Birth Date
Cosmo Kramer 111-222 2019-06-01 1979-08-12
George Costanza 131-212 2016-06-01 1980-08-12
Jerry Seinfeld 223-212 2017-06-01 1981-06-15
John Wayne 323-212 2018-06-01 1962-06-17

CodePudding user response:

Add another parameter that indicates the key to sort on, or just use the built-in sort() method which does the same thing:

class Member:
    def __init__(self, name, zip, hire_date, birth_date):
        self.id = id
        self.name = name
        self.zip = zip
        self.hire_date = hire_date
        self.birth_date = birth_date

    def get_name(self):
        return self.name

    def get_birth_date(self):
        return self.birth_date

    def get_hire_date(self):
        return self.hire_date

    def get_zip_code(self):
        return self.zip

    # Define how to print a Member
    def __str__(self):
        return f'{self.name:15} {self.zip} {self.hire_date} {self.birth_date}'

def partition(array, key, begin, end):
    pivot = begin
    for i in range(begin 1, end 1):
        if key(array[i]) <= key(array[begin]): # use key for comparison
            pivot  = 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot

def quicksort(array, key, begin=0, end=None):
    if end is None:
        end = len(array) - 1
    def _quicksort(array, key, begin, end):
        if begin >= end:
            return
        pivot = partition(array, key, begin, end)
        _quicksort(array, key, begin, pivot-1)
        _quicksort(array, key, pivot 1, end)
    return _quicksort(array, key, begin, end)

def display(L):
    print('Name            Zip     Hire Date  Birth Date')
    for item in L:
        print(item)
    print()

L =[Member('Cosmo Kramer','111-222','2019-06-01','1979-08-12'),
    Member('George Costanza','131-212','2016-06-01','1980-08-12'),
    Member('Jerry Seinfeld','223-212','2017-06-01','1981-06-15'),
    Member('John Wayne','323-212','2018-06-01','1962-06-17')]

quicksort(L,Member.get_hire_date)
display(L)
quicksort(L,Member.get_birth_date)
display(L)
# Using built-in sort()
L.sort(key=Member.get_name)
display(L)

Output:

Name            Zip     Hire Date  Birth Date
George Costanza 131-212 2016-06-01 1980-08-12
Jerry Seinfeld  223-212 2017-06-01 1981-06-15
John Wayne      323-212 2018-06-01 1962-06-17
Cosmo Kramer    111-222 2019-06-01 1979-08-12

Name            Zip     Hire Date  Birth Date
John Wayne      323-212 2018-06-01 1962-06-17
Cosmo Kramer    111-222 2019-06-01 1979-08-12
George Costanza 131-212 2016-06-01 1980-08-12
Jerry Seinfeld  223-212 2017-06-01 1981-06-15

Name            Zip     Hire Date  Birth Date
Cosmo Kramer    111-222 2019-06-01 1979-08-12
George Costanza 131-212 2016-06-01 1980-08-12
Jerry Seinfeld  223-212 2017-06-01 1981-06-15
John Wayne      323-212 2018-06-01 1962-06-17

CodePudding user response:

Refer to the implementation of Python's own sorting function:

def identity(x):
    return x

def partition(array, begin, end, key):
    pivot = begin
    for i in range(begin 1, end 1):
        if key(array[i]) <= key(array[begin]):
            pivot  = 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot

def quicksort(array, begin=0, end=None, key=identity):
    if end is None:
        end = len(array) - 1
    def _quicksort(array, begin, end):
        if begin >= end:
            return
        pivot = partition(array, begin, end, key)
        _quicksort(array, begin, pivot-1)
        _quicksort(array, pivot 1, end)
    return _quicksort(array, begin, end)

Usage:

quicksort(list_of_member, key=Member.get_name)
quicksort(list_of_member, key=Member.get_zip_code)

CodePudding user response:

You can achieve this by defining another method inside your class:

class Metric:
    b_date = "birth_date"
    h_date = "hire_date"
    zip_code = "zip_code"
    name = "name"


class Member:
    def __init__(self, name, zip, hire_date, birth_date):
        self.id = id
        self.name = name
        self.zip = zip
        self.hire_date = hire_date
        self.birth_date = birth_date

    def get_name(self):
        return self.name

    def get_birth_date(self):
        return self.birth_date

    def get_hire_date(self):
        return self.hire_date

    def get_zip_code(self):
        return self.zip

    def get_metric_value(self, metric):
        if metric == Metric.b_date:
            return self.get_birth_date()
        elif metric == Metric.h_date:
            return self.get_hire_date()
        elif metric == Metric.zip_code:
            return self.get_zip_code()
        elif metric == Metric.name:
            return self.get_name()

def partition(array, begin, end, metric):
    pivot = begin
    for i in range(begin 1, end 1):
        if array[i].get_metric_value(metric) <= array[begin].get_metric_value(metric):
            pivot  = 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot

def quicksort(array, metric, begin=0, end=None):
    if end is None:
        end = len(array) - 1
    def _quicksort(array, begin, end):
        if begin >= end:
            return
        pivot = partition(array, begin, end, metric)
        _quicksort(array, begin, pivot-1)
        _quicksort(array, pivot 1, end)
    return _quicksort(array, begin, end)

quicksort(array, Metric.zip_code)  # or any other metric ...
  • Related