ਸੋਰਟਿੰਗ ਤਕਨੀਕਾਂ

Python ਲਿਸਟਾਂ ਵਿੱਚ ਇੱਕ ਬਿਲਟ-ਇਨ list.sort() ਮੈਥਡ ਹੁੰਦਾ ਹੈ ਜੋ ਲਿਸਟ ਨੂੰ ਉਸੇ ਥਾਂ ਸੋਧਦਾ ਹੈ। ਇਸ ਤੋਂ ਇਲਾਵਾ ਇੱਕ ਬਿਲਟ-ਇਨ sorted() ਫੰਕਸ਼ਨ ਵੀ ਹੈ ਜੋ ਕਿਸੇ ਇਟਰੇਬਲ ਤੋਂ ਇੱਕ ਨਵੀਂ ਸੋਰਟ ਕੀਤੀ ਲਿਸਟ ਬਣਾਉਂਦਾ ਹੈ।

ਇਸ ਦਸਤਾਵੇਜ਼ ਵਿੱਚ ਅਸੀਂ Python ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਡਾਟਾ ਨੂੰ ਸੋਰਟ ਕਰਨ ਦੀਆਂ ਵੱਖ-ਵੱਖ ਤਕਨੀਕਾਂ ਦੀ ਪੜਚੋਲ ਕਰਾਂਗੇ।

ਸੋਰਟਿੰਗ ਦੇ ਮੁੱਢਲੇ ਸਿਧਾਂਤ

ਇੱਕ ਸਧਾਰਣ ਵੱਧਦੇ ਕ੍ਰਮ ਵਿੱਚ ਸੋਰਟ ਕਰਨਾ ਬਹੁਤ ਆਸਾਨ ਹੈ: ਸਿਰਫ਼ sorted() ਫੰਕਸ਼ਨ ਨੂੰ ਕਾਲ ਕਰੋ। ਇਹ ਇੱਕ ਨਵੀਂ ਸੋਰਟ ਕੀਤੀ ਲਿਸਟ ਵਾਪਸ ਕਰਦਾ ਹੈ:

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

ਤੁਸੀਂ list.sort() ਮੈਥਡ ਦੀ ਵੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ। ਇਹ ਲਿਸਟ ਨੂੰ ਉਸੇ ਥਾਂ ਸੋਧਦਾ ਹੈ (ਅਤੇ ਗਲਤਫਹਿਮੀ ਤੋਂ ਬਚਣ ਲਈ None ਵਾਪਸ ਕਰਦਾ ਹੈ)। ਆਮ ਤੌਰ 'ਤੇ ਇਹ sorted() ਨਾਲੋਂ ਘੱਟ ਸੁਵਿਧਾਜਨਕ ਹੁੰਦਾ ਹੈ, ਪਰ ਜੇ ਤੁਹਾਨੂੰ ਮੂਲ ਲਿਸਟ ਦੀ ਲੋੜ ਨਹੀਂ ਹੈ ਤਾਂ ਇਹ ਥੋੜ੍ਹਾ ਵੱਧ ਕਾਰਗਰ ਹੈ।

>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]

ਇੱਕ ਹੋਰ ਫਰਕ ਇਹ ਹੈ ਕਿ list.sort() ਮੈਥਡ ਸਿਰਫ਼ ਲਿਸਟਾਂ ਲਈ ਹੀ ਪਰਿਭਾਸ਼ਿਤ ਹੈ। ਇਸਦੇ ਉਲਟ, sorted() ਫੰਕਸ਼ਨ ਕਿਸੇ ਵੀ ਇਟਰੇਬਲ ਨੂੰ ਸਵੀਕਾਰ ਕਰਦਾ ਹੈ।

>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]

Key ਫੰਕਸ਼ਨ

list.sort() ਮੈਥਡ ਅਤੇ sorted(), min(), max(), heapq.nsmallest() ਅਤੇ heapq.nlargest() ਫੰਕਸ਼ਨਾਂ ਵਿੱਚ ਇੱਕ key ਪੈਰਾਮੀਟਰ ਹੁੰਦਾ ਹੈ ਜੋ ਤੁਲਨਾ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਹਰ ਲਿਸਟ ਐਲੀਮੈਂਟ ਉੱਤੇ ਕਾਲ ਕੀਤੇ ਜਾਣ ਵਾਲੇ ਫੰਕਸ਼ਨ (ਜਾਂ ਹੋਰ callable) ਨੂੰ ਨਿਰਧਾਰਤ ਕਰਦਾ ਹੈ।

ਉਦਾਹਰਨ ਵਜੋਂ, ਇੱਥੇ str.casefold() ਦੀ ਵਰਤੋਂ ਕਰਕੇ case-insensitive ਸਟਰਿੰਗ ਤੁਲਨਾ ਦਿਖਾਈ ਗਈ ਹੈ:

>>> sorted("This is a test string from Andrew".split(), key=str.casefold)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

key ਪੈਰਾਮੀਟਰ ਦਾ ਮੁੱਲ ਇੱਕ ਫੰਕਸ਼ਨ (ਜਾਂ ਹੋਰ callable) ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ ਜੋ ਇੱਕ ਇਕੱਲਾ argument ਲੈਂਦਾ ਹੈ ਅਤੇ ਸੋਰਟਿੰਗ ਲਈ ਵਰਤੀ ਜਾਣ ਵਾਲੀ key ਵਾਪਸ ਕਰਦਾ ਹੈ। ਇਹ ਤਕਨੀਕ ਤੇਜ਼ ਹੈ ਕਿਉਂਕਿ key function ਹਰ ਇਨਪੁੱਟ ਰਿਕਾਰਡ ਲਈ ਸਿਰਫ਼ ਇੱਕ ਵਾਰ ਕਾਲ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।

ਇੱਕ ਆਮ ਪੈਟਰਨ ਇਹ ਹੈ ਕਿ ਜਟਿਲ objects ਨੂੰ object ਦੇ ਕੁਝ indices ਨੂੰ key ਵਜੋਂ ਵਰਤ ਕੇ ਸੋਰਟ ਕੀਤਾ ਜਾਵੇ। ਉਦਾਹਰਨ ਲਈ:

>>> student_tuples = [
... ('john', 'A', 15),
... ('jane', 'B', 12),
... ('dave', 'B', 10),
... ]
>>> sorted(student_tuples, key=lambda student: student[2]) # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

ਇਹੀ ਤਕਨੀਕ ਨਾਮਿਤ attributes ਵਾਲੇ objects ਲਈ ਵੀ ਕੰਮ ਕਰਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ:

>>> class Student:
... def __init__(self, name, grade, age):
... self.name = name
... self.grade = grade
... self.age = age
... def __repr__(self):
... return repr((self.name, self.grade, self.age))

>>> student_objects = [
... Student('john', 'A', 15),
... Student('jane', 'B', 12),
... Student('dave', 'B', 10),
... ]
>>> sorted(student_objects, key=lambda student: student.age) # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

ਨਾਮਿਤ attributes ਵਾਲੇ objects ਇੱਕ ਆਮ class ਰਾਹੀਂ ਬਣਾਏ ਜਾ ਸਕਦੇ ਹਨ, ਜਿਵੇਂ ਉੱਪਰ ਦਿਖਾਇਆ ਗਿਆ ਹੈ, ਜਾਂ ਉਹ dataclass ਜਾਂ named tuple ਦੇ instances ਵੀ ਹੋ ਸਕਦੇ ਹਨ।

ਓਪਰੇਟਰ ਮੋਡੀਊਲ ਫੰਕਸ਼ਨ ਅਤੇ Partial Function Evaluation

ਉੱਪਰ ਦਿਖਾਏ ਗਏ key function ਪੈਟਰਨ ਬਹੁਤ ਆਮ ਹਨ, ਇਸ ਲਈ Python ਐਕਸੈਸਰ ਫੰਕਸ਼ਨਾਂ ਨੂੰ ਹੋਰ ਆਸਾਨ ਅਤੇ ਤੇਜ਼ ਬਣਾਉਣ ਲਈ ਸੁਵਿਧਾਜਨਕ ਫੰਕਸ਼ਨ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ। operator ਮੋਡੀਊਲ ਵਿੱਚ itemgetter(), attrgetter() ਅਤੇ methodcaller() ਫੰਕਸ਼ਨ ਉਪਲਬਧ ਹਨ।

ਇਨ੍ਹਾਂ ਫੰਕਸ਼ਨਾਂ ਦੀ ਵਰਤੋਂ ਨਾਲ ਉੱਪਰ ਦਿੱਤੀਆਂ ਉਦਾਹਰਨਾਂ ਹੋਰ ਸਧਾਰਣ ਅਤੇ ਤੇਜ਼ ਬਣ ਜਾਂਦੀਆਂ ਹਨ:

>>> from operator import itemgetter, attrgetter

>>> sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

>>> sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

ਓਪਰੇਟਰ ਮੋਡੀਊਲ ਦੇ ਫੰਕਸ਼ਨ ਬਹੁ-ਪੱਧਰੀ ਸੋਰਟਿੰਗ ਦੀ ਆਗਿਆ ਦਿੰਦੇ ਹਨ। ਉਦਾਹਰਨ ਲਈ, ਪਹਿਲਾਂ grade ਅਤੇ ਫਿਰ age ਦੇ ਅਧਾਰ 'ਤੇ ਸੋਰਟ ਕਰਨ ਲਈ:

>>> sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

>>> sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

functools ਮੋਡੀਊਲ key functions ਬਣਾਉਣ ਲਈ ਇੱਕ ਹੋਰ ਲਾਭਦਾਇਕ ਸਾਧਨ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ। partial() ਫੰਕਸ਼ਨ ਬਹੁ-ਆਰਗੂਮੈਂਟ ਫੰਕਸ਼ਨ ਦੀ arity ਘਟਾ ਸਕਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਉਹ key function ਵਜੋਂ ਵਰਤਣ ਲਈ ਉਚਿਤ ਬਣ ਜਾਂਦਾ ਹੈ।

>>> from functools import partial
>>> from unicodedata import normalize

>>> names = 'Zoë Åbjørn Núñez Élana Zeke Abe Nubia Eloise'.split()

>>> sorted(names, key=partial(normalize, 'NFD'))
['Abe', 'Åbjørn', 'Eloise', 'Élana', 'Nubia', 'Núñez', 'Zeke', 'Zoë']

>>> sorted(names, key=partial(normalize, 'NFC'))
['Abe', 'Eloise', 'Nubia', 'Núñez', 'Zeke', 'Zoë', 'Åbjørn', 'Élana']

ਵੱਧਦਾ ਅਤੇ ਘਟਦਾ ਕ੍ਰਮ

list.sort() ਅਤੇ sorted() ਦੋਵੇਂ reverse ਪੈਰਾਮੀਟਰ ਨੂੰ ਸਵੀਕਾਰ ਕਰਦੇ ਹਨ, ਜਿਸਦਾ ਮੁੱਲ boolean ਹੁੰਦਾ ਹੈ। ਇਸਦੀ ਵਰਤੋਂ ਘਟਦੇ ਕ੍ਰਮ ਵਿੱਚ ਸੋਰਟ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਵਿਦਿਆਰਥੀਆਂ ਦੇ ਡਾਟਾ ਨੂੰ ਉਲਟੇ age ਕ੍ਰਮ ਵਿੱਚ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ:

>>> sorted(student_tuples, key=itemgetter(2), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

>>> sorted(student_objects, key=attrgetter('age'), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

ਸੋਰਟ ਸਥਿਰਤਾ ਅਤੇ ਜਟਿਲ ਸੋਰਟਿੰਗ

ਸੋਰਟਿੰਗ ਦੇ stable ਹੋਣ ਦੀ ਗਾਰੰਟੀ ਹੈ। ਇਸਦਾ ਅਰਥ ਹੈ ਕਿ ਜਦੋਂ ਕਈ ਰਿਕਾਰਡਾਂ ਦੀ key ਇੱਕੋ ਜਿਹੀ ਹੋਵੇ, ਤਾਂ ਉਨ੍ਹਾਂ ਦਾ ਮੂਲ ਕ੍ਰਮ ਬਰਕਰਾਰ ਰਹਿੰਦਾ ਹੈ।

>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]

ਧਿਆਨ ਦਿਓ ਕਿ blue ਵਾਲੇ ਦੋਵੇਂ ਰਿਕਾਰਡ ਆਪਣਾ ਮੂਲ ਕ੍ਰਮ ਬਰਕਰਾਰ ਰੱਖਦੇ ਹਨ, ਇਸ ਲਈ ('blue', 1) ਹਮੇਸ਼ਾਂ ('blue', 2) ਤੋਂ ਪਹਿਲਾਂ ਰਹੇਗਾ।

ਇਹ ਸ਼ਾਨਦਾਰ ਵਿਸ਼ੇਸ਼ਤਾ ਤੁਹਾਨੂੰ ਕਈ ਸੋਰਟਿੰਗ ਕਦਮਾਂ ਦੀ ਲੜੀ ਰਾਹੀਂ ਜਟਿਲ ਸੋਰਟਿੰਗ ਬਣਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਵਿਦਿਆਰਥੀ ਡਾਟਾ ਨੂੰ ਘਟਦੇ grade ਅਤੇ ਫਿਰ ਵੱਧਦੇ age ਅਨੁਸਾਰ ਸੋਰਟ ਕਰਨ ਲਈ, ਪਹਿਲਾਂ age ਅਨੁਸਾਰ ਸੋਰਟ ਕਰੋ ਅਤੇ ਫਿਰ grade ਅਨੁਸਾਰ ਮੁੜ ਸੋਰਟ ਕਰੋ:

>>> s = sorted(student_objects, key=attrgetter('age')) # sort on secondary key
>>> sorted(s, key=attrgetter('grade'), reverse=True) # now sort on primary key, descending
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

ਇਸ ਵਿਚਾਰ ਨੂੰ ਇੱਕ wrapper function ਵਿੱਚ ਬਦਲਿਆ ਜਾ ਸਕਦਾ ਹੈ ਜੋ ਲਿਸਟ ਅਤੇ field तथा order ਵਾਲੀਆਂ tuples ਨੂੰ ਸਵੀਕਾਰ ਕਰਕੇ ਕਈ ਪਾਸਾਂ ਵਿੱਚ ਸੋਰਟ ਕਰ ਸਕਦਾ ਹੈ।

>>> def multisort(xs, specs):
... for key, reverse in reversed(specs):
... xs.sort(key=attrgetter(key), reverse=reverse)
... return xs

>>> multisort(list(student_objects), (('grade', True), ('age', False)))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

Python ਵਿੱਚ ਵਰਤਿਆ ਜਾਣ ਵਾਲਾ Timsort ਐਲਗੋਰਿਦਮ ਕਈ ਸੋਰਟਿੰਗ ਕਾਰਵਾਈਆਂ ਨੂੰ ਬਹੁਤ ਕੁਸ਼ਲਤਾ ਨਾਲ ਕਰਦਾ ਹੈ ਕਿਉਂਕਿ ਇਹ ਡਾਟਾਸੈੱਟ ਵਿੱਚ ਪਹਿਲਾਂ ਤੋਂ ਮੌਜੂਦ ਕ੍ਰਮਬੱਧਤਾ ਦਾ ਲਾਭ ਉਠਾ ਸਕਦਾ ਹੈ।

ਸਜਾਓ-ਸੋਰਟ ਕਰੋ-ਸਜਾਵਟ ਹਟਾਓ

ਇਸ idiom ਨੂੰ Decorate-Sort-Undecorate ਕਿਹਾ ਜਾਂਦਾ ਹੈ ਕਿਉਂਕਿ ਇਹ ਤਿੰਨ ਕਦਮਾਂ 'ਤੇ ਆਧਾਰਿਤ ਹੈ:

  • ਸਭ ਤੋਂ ਪਹਿਲਾਂ, ਮੂਲ ਲਿਸਟ ਨੂੰ ਨਵੇਂ ਮੁੱਲਾਂ ਨਾਲ ਸਜਾਇਆ ਜਾਂਦਾ ਹੈ ਜੋ ਸੋਰਟਿੰਗ ਕ੍ਰਮ ਨੂੰ ਨਿਯੰਤਰਿਤ ਕਰਦੇ ਹਨ।

  • ਦੂਜੇ ਕਦਮ ਵਿੱਚ, ਸਜਾਈ ਗਈ ਲਿਸਟ ਨੂੰ ਸੋਰਟ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।

  • ਅੰਤ ਵਿੱਚ, ਸਜਾਵਟਾਂ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਇੱਕ ਐਸੀ ਲਿਸਟ ਬਣਦੀ ਹੈ ਜਿਸ ਵਿੱਚ ਨਵੇਂ ਕ੍ਰਮ ਵਿੱਚ ਸਿਰਫ਼ ਮੂਲ ਮੁੱਲ ਹੀ ਰਹਿੰਦੇ ਹਨ।

ਉਦਾਹਰਨ ਲਈ, DSU ਵਿਧੀ ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਵਿਦਿਆਰਥੀ ਡਾਟਾ ਨੂੰ grade ਅਨੁਸਾਰ ਸੋਰਟ ਕਰਨ ਲਈ:

>>> decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
>>> decorated.sort()
>>> [student for grade, i, student in decorated] # undecorate
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

ਇਹ idiom ਇਸ ਲਈ ਕੰਮ ਕਰਦਾ ਹੈ ਕਿਉਂਕਿ tuples ਦੀ ਤੁਲਨਾ lexicographical ਢੰਗ ਨਾਲ ਕੀਤੀ ਜਾਂਦੀ ਹੈ; ਪਹਿਲਾਂ ਪਹਿਲੇ ਆਈਟਮਾਂ ਦੀ ਤੁਲਨਾ ਹੁੰਦੀ ਹੈ, ਜੇ ਉਹ ਇੱਕੋ ਜਿਹੇ ਹੋਣ ਤਾਂ ਦੂਜੇ ਆਈਟਮਾਂ ਦੀ, ਅਤੇ ਇਸੇ ਤਰ੍ਹਾਂ ਅੱਗੇ।

ਸਜਾਈ ਗਈ ਲਿਸਟ ਵਿੱਚ index i ਸ਼ਾਮਲ ਕਰਨਾ ਹਰ ਮਾਮਲੇ ਵਿੱਚ ਲਾਜ਼ਮੀ ਨਹੀਂ ਹੈ, ਪਰ ਇਸਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਨਾਲ ਦੋ ਲਾਭ ਮਿਲਦੇ ਹਨ:

  • ਸੋਰਟ ਸਥਿਰ ਰਹਿੰਦਾ ਹੈ -- ਜੇ ਦੋ ਆਈਟਮਾਂ ਦੀ key ਇੱਕੋ ਜਿਹੀ ਹੋਵੇ, ਤਾਂ ਉਨ੍ਹਾਂ ਦਾ ਕ੍ਰਮ ਸੋਰਟ ਕੀਤੀ ਲਿਸਟ ਵਿੱਚ ਬਰਕਰਾਰ ਰਹੇਗਾ।

  • ਸੋਰਟ ਸਥਿਰ ਰਹਿੰਦਾ ਹੈ -- ਜੇ ਦੋ ਆਈਟਮਾਂ ਦੀ key ਇੱਕੋ ਜਿਹੀ ਹੋਵੇ, ਤਾਂ ਉਨ੍ਹਾਂ ਦਾ ਕ੍ਰਮ ਸੋਰਟ ਕੀਤੀ ਲਿਸਟ ਵਿੱਚ ਬਰਕਰਾਰ ਰਹੇਗਾ।

ਇਸ idiom ਦਾ ਇੱਕ ਹੋਰ ਨਾਮ Schwartzian transform ਵੀ ਹੈ, ਜਿਸਦਾ ਨਾਮ Randal L. Schwartz ਦੇ ਨਾਮ 'ਤੇ ਰੱਖਿਆ ਗਿਆ ਹੈ, ਜਿਨ੍ਹਾਂ ਨੇ ਇਸਨੂੰ Perl ਪ੍ਰੋਗਰਾਮਰਾਂ ਵਿੱਚ ਲੋਕਪ੍ਰਿਯ ਬਣਾਇਆ।

ਹੁਣ ਜਦੋਂ Python ਸੋਰਟਿੰਗ ਵਿੱਚ key functions ਉਪਲਬਧ ਹਨ, ਇਹ ਤਕਨੀਕ ਅਕਸਰ ਲੋੜੀਂਦੀ ਨਹੀਂ ਰਹਿੰਦੀ।

Comparison Functions

ਉਨ੍ਹਾਂ key functions ਤੋਂ ਵੱਖਰੇ ਜੋ ਸੋਰਟਿੰਗ ਲਈ ਇੱਕ ਨਿਰਪੱਖ ਮੁੱਲ ਵਾਪਸ ਕਰਦੇ ਹਨ, ਇੱਕ comparison function ਦੋ ਇਨਪੁੱਟਾਂ ਲਈ ਸਾਪੇਖ ਕ੍ਰਮ ਨਿਰਧਾਰਤ ਕਰਦਾ ਹੈ।

ਉਦਾਹਰਨ ਲਈ, ਇੱਕ balance scale ਦੋ ਨਮੂਨਿਆਂ ਦੀ ਤੁਲਨਾ ਕਰਕੇ ਉਨ੍ਹਾਂ ਦਾ ਸਾਪੇਖ ਕ੍ਰਮ ਦੱਸਦਾ ਹੈ: ਹਲਕਾ, ਬਰਾਬਰ ਜਾਂ ਭਾਰੀ। ਇਸੇ ਤਰ੍ਹਾਂ, cmp(a, b) ਵਰਗਾ comparison function ਘੱਟ ਹੋਣ ਲਈ ਨਕਾਰਾਤਮਕ ਮੁੱਲ, ਬਰਾਬਰ ਹੋਣ ਲਈ ਸਿਫ਼ਰ ਅਤੇ ਵੱਧ ਹੋਣ ਲਈ ਸਕਾਰਾਤਮਕ ਮੁੱਲ ਵਾਪਸ ਕਰੇਗਾ।

ਦੂਜੀਆਂ ਭਾਸ਼ਾਵਾਂ ਤੋਂ ਐਲਗੋਰਿਦਮਾਂ ਦਾ ਅਨੁਵਾਦ ਕਰਦੇ ਸਮੇਂ comparison functions ਦਾ ਸਾਹਮਣਾ ਕਰਨਾ ਆਮ ਗੱਲ ਹੈ। ਇਸ ਤੋਂ ਇਲਾਵਾ, ਕੁਝ ਲਾਇਬ੍ਰੇਰੀਆਂ ਆਪਣੀ API ਦੇ ਹਿੱਸੇ ਵਜੋਂ comparison functions ਪ੍ਰਦਾਨ ਕਰਦੀਆਂ ਹਨ। ਉਦਾਹਰਨ ਲਈ, locale.strcoll() ਇੱਕ comparison function ਹੈ।

ਅਜਿਹੀਆਂ ਸਥਿਤੀਆਂ ਨੂੰ ਸੰਭਾਲਣ ਲਈ, Python functools.cmp_to_key ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ ਜੋ comparison function ਨੂੰ wrap ਕਰਕੇ ਉਸਨੂੰ key function ਵਜੋਂ ਵਰਤਣ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ:

sorted(words, key=cmp_to_key(strcoll)) # locale-aware sort order

ਅਸੋਰਟਯੋਗ ਕਿਸਮਾਂ ਅਤੇ ਮੁੱਲਾਂ ਲਈ ਰਣਨੀਤੀਆਂ

ਸੋਰਟਿੰਗ ਦੌਰਾਨ ਕਿਸਮਾਂ ਅਤੇ ਮੁੱਲਾਂ ਨਾਲ ਸੰਬੰਧਿਤ ਕਈ ਸਮੱਸਿਆਵਾਂ ਆ ਸਕਦੀਆਂ ਹਨ। ਹੇਠਾਂ ਕੁਝ ਰਣਨੀਤੀਆਂ ਦਿੱਤੀਆਂ ਗਈਆਂ ਹਨ ਜੋ ਮਦਦਗਾਰ ਸਾਬਤ ਹੋ ਸਕਦੀਆਂ ਹਨ:

  • ਸੋਰਟ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਗੈਰ-ਤੁਲਨਾਯੋਗ ਇਨਪੁੱਟ ਕਿਸਮਾਂ ਨੂੰ strings ਵਿੱਚ ਬਦਲੋ:

>>> data = ['twelve', '11', 10]
>>> sorted(map(str, data))
['10', '11', 'twelve']

ਇਹ ਇਸ ਲਈ ਲੋੜੀਂਦਾ ਹੈ ਕਿਉਂਕਿ ਜ਼ਿਆਦਾਤਰ ਵੱਖ-ਵੱਖ ਕਿਸਮਾਂ ਦੀਆਂ ਤੁਲਨਾਵਾਂ TypeError ਪੈਦਾ ਕਰਦੀਆਂ ਹਨ।

  • ਸੋਰਟ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਖ਼ਾਸ ਮੁੱਲਾਂ ਨੂੰ ਹਟਾਓ:

>>> from math import isnan
>>> from itertools import filterfalse
>>> data = [3.3, float('nan'), 1.1, 2.2]
>>> sorted(filterfalse(isnan, data))
[1.1, 2.2, 3.3]

ਇਹ ਇਸ ਲਈ ਲੋੜੀਂਦਾ ਹੈ ਕਿਉਂਕਿ IEEE-754 standard ਦੇ ਅਨੁਸਾਰ, "ਹਰ NaN ਹਰ ਚੀਜ਼ ਨਾਲ, ਆਪਣੇ ਆਪ ਸਮੇਤ, ਬੇਤਰਤੀਬ ਤਰੀਕੇ ਨਾਲ ਤੁਲਨਾ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"

ਇਸੇ ਤਰ੍ਹਾਂ, None ਨੂੰ ਵੀ ਡਾਟਾਸੈੱਟਾਂ ਵਿੱਚੋਂ ਹਟਾਇਆ ਜਾ ਸਕਦਾ ਹੈ:

>>> data = [3.3, None, 1.1, 2.2]
>>> sorted(x for x in data if x is not None)
[1.1, 2.2, 3.3]

ਇਹ ਇਸ ਲਈ ਲੋੜੀਂਦਾ ਹੈ ਕਿਉਂਕਿ None ਹੋਰ ਕਿਸਮਾਂ ਨਾਲ ਤੁਲਨਾਯੋਗ ਨਹੀਂ ਹੈ।

  • ਸੋਰਟ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ mapping ਕਿਸਮਾਂ ਨੂੰ ਸੋਰਟ ਕੀਤੀਆਂ item lists ਵਿੱਚ ਬਦਲੋ:

>>> data = [{'a': 1}, {'b': 2}]
>>> sorted(data, key=lambda d: sorted(d.items()))
[{'a': 1}, {'b': 2}]

ਇਹ ਇਸ ਲਈ ਲੋੜੀਂਦਾ ਹੈ ਕਿਉਂਕਿ dict-to-dict ਤੁਲਨਾਵਾਂ TypeError ਪੈਦਾ ਕਰਦੀਆਂ ਹਨ।

  • ਸੋਰਟ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ set ਕਿਸਮਾਂ ਨੂੰ ਸੋਰਟ ਕੀਤੀਆਂ ਲਿਸਟਾਂ ਵਿੱਚ ਬਦਲੋ:

>>> data = [{'a', 'b', 'c'}, {'b', 'c', 'd'}]
>>> sorted(map(sorted, data))
[['a', 'b', 'c'], ['b', 'c', 'd']]

ਇਹ ਇਸ ਲਈ ਲੋੜੀਂਦਾ ਹੈ ਕਿਉਂਕਿ set ਕਿਸਮਾਂ ਵਿੱਚ ਮੌਜੂਦ ਐਲੀਮੈਂਟਾਂ ਦਾ ਕ੍ਰਮ ਨਿਰਧਾਰਤ ਨਹੀਂ ਹੁੰਦਾ। ਉਦਾਹਰਨ ਲਈ, list({'a', 'b'}) ਕਦੇ ['a', 'b'] ਅਤੇ ਕਦੇ ['b', 'a'] ਪੈਦਾ ਕਰ ਸਕਦਾ ਹੈ।

ਕੁਝ ਹੋਰ ਲਾਭਦਾਇਕ ਜਾਣਕਾਰੀਆਂ

  • locale-aware ਸੋਰਟਿੰਗ ਲਈ, key function ਵਜੋਂ locale.strxfrm() ਜਾਂ comparison function ਵਜੋਂ locale.strcoll() ਦੀ ਵਰਤੋਂ ਕਰੋ। ਇਹ ਇਸ ਲਈ ਲਾਜ਼ਮੀ ਹੈ ਕਿਉਂਕਿ "alphabetical" ਸੋਰਟ ਕ੍ਰਮ ਵੱਖ-ਵੱਖ ਸਭਿਆਚਾਰਾਂ ਵਿੱਚ ਵੱਖ ਹੋ ਸਕਦੇ ਹਨ ਭਾਵੇਂ ਮੂਲ ਵਰਣਮਾਲਾ ਇੱਕੋ ਹੀ ਹੋਵੇ।

  • reverse ਪੈਰਾਮੀਟਰ ਸੋਰਟ ਸਥਿਰਤਾ ਨੂੰ ਫਿਰ ਵੀ ਕਾਇਮ ਰੱਖਦਾ ਹੈ (ਅਰਥਾਤ ਇੱਕੋ key ਵਾਲੇ ਰਿਕਾਰਡ ਆਪਣਾ ਮੂਲ ਕ੍ਰਮ ਬਰਕਰਾਰ ਰੱਖਦੇ ਹਨ)। ਦਿਲਚਸਪ ਗੱਲ ਇਹ ਹੈ ਕਿ ਇਸ ਪ੍ਰਭਾਵ ਨੂੰ reversed() ਬਿਲਟ-ਇਨ ਫੰਕਸ਼ਨ ਦੀ ਦੋ ਵਾਰ ਵਰਤੋਂ ਕਰਕੇ ਵੀ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ:

    >>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
    >>> standard_way = sorted(data, key=itemgetter(0), reverse=True)
    >>> double_reversed = list(reversed(sorted(reversed(data), key=itemgetter(0))))
    >>> assert standard_way == double_reversed
    >>> standard_way
    [('red', 1), ('red', 2), ('blue', 1), ('blue', 2)]
    
  • ਦੋ objects ਵਿਚਕਾਰ ਤੁਲਨਾ ਕਰਦੇ ਸਮੇਂ ਸੋਰਟ ਰੂਟੀਨ < ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹਨ। ਇਸ ਲਈ, __lt__() ਮੈਥਡ ਨੂੰ ਪਰਿਭਾਸ਼ਿਤ ਕਰਕੇ ਕਿਸੇ class ਲਈ ਇੱਕ ਮਿਆਰੀ ਸੋਰਟ ਕ੍ਰਮ ਜੋੜਨਾ ਆਸਾਨ ਹੈ:

    >>> Student.__lt__ = lambda self, other: self.age < other.age
    >>> sorted(student_objects)
    [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
    

    ਹਾਲਾਂਕਿ, ਧਿਆਨ ਰੱਖੋ ਕਿ <, ਜੇ __lt__() ਲਾਗੂ ਨਾ ਕੀਤਾ ਗਿਆ ਹੋਵੇ, ਤਾਂ __gt__() ਵਰਤਣ 'ਤੇ ਵਾਪਸ ਆ ਸਕਦਾ ਹੈ (ਮਕੈਨਿਕਸ ਦੀਆਂ ਵਿਸਥਾਰਾਂ ਲਈ object.__lt__() ਵੇਖੋ). ਅਚਾਨਕ ਨਤੀਜਿਆਂ ਤੋਂ ਬਚਣ ਲਈ, PEP 8 ਸਿਫਾਰਸ਼ ਕਰਦਾ ਹੈ ਕਿ ਸਾਰੇ ਛੇ ਤੁਲਨਾ ਵਿਧੀਆਂ ਲਾਗੂ ਕੀਤੀਆਂ ਜਾਣ. ਇਸ ਕੰਮ ਨੂੰ ਆਸਾਨ ਬਣਾਉਣ ਲਈ @~functools.total_ordering ਡੈਕੋਰੇਟਰ ਮੁਹੱਈਆ ਕੀਤਾ ਗਿਆ ਹੈ.

  • Key functions ਦਾ ਸਿੱਧੇ ਤੌਰ 'ਤੇ ਸੋਰਟ ਕੀਤੇ ਜਾ ਰਹੇ objects 'ਤੇ ਨਿਰਭਰ ਹੋਣਾ ਲਾਜ਼ਮੀ ਨਹੀਂ ਹੈ। ਇੱਕ key function ਬਾਹਰੀ ਸਰੋਤਾਂ ਤੱਕ ਵੀ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਜੇ ਵਿਦਿਆਰਥੀਆਂ ਦੇ grades ਇੱਕ dictionary ਵਿੱਚ ਸਟੋਰ ਕੀਤੇ ਹੋਣ, ਤਾਂ ਉਹਨਾਂ ਦੀ ਵਰਤੋਂ ਵਿਦਿਆਰਥੀਆਂ ਦੇ ਨਾਂਵਾਂ ਦੀ ਵੱਖਰੀ ਲਿਸਟ ਨੂੰ ਸੋਰਟ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ:

    >>> students = ['dave', 'john', 'jane']
    >>> newgrades = {'john': 'F', 'jane':'A', 'dave': 'C'}
    >>> sorted(students, key=newgrades.__getitem__)
    ['jane', 'dave', 'john']
    

ਅੰਸ਼ਿਕ ਸੋਰਟਿੰਗ

ਕੁਝ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵਿੱਚ ਸਿਰਫ਼ ਕੁਝ ਡਾਟੇ ਨੂੰ ਹੀ ਕ੍ਰਮਬੱਧ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ। ਮਿਆਰੀ ਲਾਇਬ੍ਰੇਰੀ ਕਈ ਅਜਿਹੇ ਸਾਧਨ ਪ੍ਰਦਾਨ ਕਰਦੀ ਹੈ ਜੋ ਪੂਰੀ ਸੋਰਟਿੰਗ ਨਾਲੋਂ ਘੱਟ ਕੰਮ ਕਰਦੇ ਹਨ:

  • min() ਅਤੇ max() ਕ੍ਰਮਵਾਰ ਸਭ ਤੋਂ ਛੋਟੇ ਅਤੇ ਸਭ ਤੋਂ ਵੱਡੇ ਮੁੱਲ ਵਾਪਸ ਕਰਦੇ ਹਨ। ਇਹ ਫੰਕਸ਼ਨ ਇਨਪੁੱਟ ਡਾਟੇ ਉੱਤੇ ਸਿਰਫ਼ ਇੱਕ ਵਾਰ ਗੁਜ਼ਰਦੇ ਹਨ ਅਤੇ ਲਗਭਗ ਕੋਈ ਵਾਧੂ ਮੈਮੋਰੀ ਨਹੀਂ ਮੰਗਦੇ।

  • heapq.nsmallest() ਅਤੇ heapq.nlargest() ਕ੍ਰਮਵਾਰ n ਸਭ ਤੋਂ ਛੋਟੇ ਅਤੇ ਸਭ ਤੋਂ ਵੱਡੇ ਮੁੱਲ ਵਾਪਸ ਕਰਦੇ ਹਨ। ਇਹ ਫੰਕਸ਼ਨ ਡਾਟੇ ਉੱਤੇ ਇੱਕ ਵਾਰ ਗੁਜ਼ਰਦੇ ਹਨ ਅਤੇ ਇੱਕ ਸਮੇਂ ਵਿੱਚ ਸਿਰਫ਼ n ਐਲੀਮੈਂਟ ਮੈਮੋਰੀ ਵਿੱਚ ਰੱਖਦੇ ਹਨ। ਜਦੋਂ n ਦਾ ਮੁੱਲ ਕੁੱਲ ਇਨਪੁੱਟਾਂ ਦੇ ਮੁਕਾਬਲੇ ਛੋਟਾ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਇਹ ਫੰਕਸ਼ਨ ਪੂਰੀ ਸੋਰਟਿੰਗ ਨਾਲੋਂ ਕਾਫ਼ੀ ਘੱਟ ਤੁਲਨਾਵਾਂ ਕਰਦੇ ਹਨ।

  • heapq.heappush() ਅਤੇ heapq.heappop() ਡਾਟੇ ਦੀ ਇੱਕ ਅੰਸ਼ਿਕ ਤੌਰ 'ਤੇ ਸੋਰਟ ਕੀਤੀ ਬਣਤਰ ਤਿਆਰ ਅਤੇ ਸੰਭਾਲਦੇ ਹਨ ਜਿਸ ਵਿੱਚ ਸਭ ਤੋਂ ਛੋਟਾ ਐਲੀਮੈਂਟ ਸਥਿਤੀ 0 'ਤੇ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਇਹ ਫੰਕਸ਼ਨ priority queues ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਉਚਿਤ ਹਨ, ਜਿਨ੍ਹਾਂ ਦੀ ਵਰਤੋਂ ਆਮ ਤੌਰ 'ਤੇ ਕਾਰਜਾਂ ਦੀ scheduling ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।