Skip to content

Commit 6e80fb8

Browse files
authored
Merge pull request #605 from dodona-edu/perf/native-sort
Performance: replace custom sort by native sort
2 parents b59c249 + 2718bc6 commit 6e80fb8

File tree

1 file changed

+23
-77
lines changed

1 file changed

+23
-77
lines changed

tested/utils.py

Lines changed: 23 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ def sorted_no_duplicates(
173173
key: Callable[[T], K] = lambda x: x,
174174
recursive_key: Callable[[K], K] | None = None,
175175
) -> list[T]:
176+
from functools import cmp_to_key
177+
176178
# Order functions
177179
def type_order(x: Any, y: Any) -> int:
178180
"""
@@ -233,86 +235,30 @@ def order(x: Any, y: Any) -> int:
233235
return int(x < y) - int(x > y) # type: ignore
234236
except TypeError:
235237
# These types cannot be compared, so fallback to string comparison.
236-
return str(x) < str(y)
238+
return int(str(x) < str(y)) - int(str(x) > str(y))
237239

238-
# Sort functions, custom implementation needed for efficient recursive ordering
239-
# of values that have different types
240-
def insertion_sort(list_t: list[T], start: int, end: int) -> list[T]:
241-
"""
242-
Insertion sort
243-
:param list_t: list to sort
244-
:param start: start of range to sort
245-
:param end: end of range to sort
246-
:return: the list itself
247-
"""
248-
for i in range(start + 1, end):
249-
j = i - 1
250-
item = list_t[i]
251-
item_key = key(item)
252-
while j >= start and order(key(list_t[j]), item_key) < 0:
253-
list_t[j + 1] = list_t[j]
254-
j -= 1
255-
list_t[j + 1] = item
256-
return list_t
257-
258-
def merge(to_list: list[T], from_list: list[T], start: int, middle: int, end: int):
259-
"""
260-
Merge two sorted sublist to sorted list
261-
262-
:param to_list: output list
263-
:param from_list: input list
264-
:param start: start of first half
265-
:param middle: end of first half, start of second half
266-
:param end: end of second half
267-
:return: No return value
268-
"""
269-
i, j, k = start, middle, start
270-
while i < middle and j < end:
271-
if order(key(from_list[i]), key(from_list[j])) > 0:
272-
to_list[k] = from_list[i]
273-
i += 1
274-
else:
275-
to_list[k] = from_list[j]
276-
j += 1
277-
k += 1
278-
if i < middle:
279-
to_list[k:end] = from_list[i:middle]
280-
else:
281-
to_list[k:end] = from_list[j:end]
240+
# Use Python's built-in sorted with cmp_to_key for performance.
241+
# We negate the order result because `order` returns 1 for x < y,
242+
# but cmp expects -1 for x < y.
243+
wrapped_key = cmp_to_key(lambda x, y: -order(x, y))
282244

283-
def timsort(list_t: list[T], timgroup: int = 32) -> list[T]:
284-
"""
285-
Time sort algorithm
286-
:param list_t: the modifiable list to sort
287-
:param timgroup: the number of elements to sort with insertion sort
288-
:return: The sort list
289-
"""
290-
len_list_t = len(list_t)
291-
for i in range(0, len_list_t, timgroup):
292-
insertion_sort(list_t, i, min(i + timgroup, len_list_t))
293-
copy = list(list_t)
294-
while timgroup < len_list_t:
295-
for start in range(0, len_list_t, 2 * timgroup):
296-
middle = min(len_list_t, start + timgroup)
297-
end = min(len_list_t, start + 2 * timgroup)
298-
merge(list_t, copy, start, middle, end)
299-
list_t, copy = copy, list_t
300-
timgroup *= 2
301-
return copy
302-
303-
# Sort and filterout duplicates
304-
first, last_key, no_dup, list_iter = True, None, [], list(iterable)
305-
for v in timsort(list_iter):
306-
if not first:
307-
key_v = key(v)
308-
if order(key_v, last_key) == 0:
309-
continue
310-
else:
311-
no_dup.append(v)
312-
last_key = key_v
313-
else:
314-
first, last_key = False, key(v)
245+
sorted_iter = sorted(iterable, key=lambda x: wrapped_key(key(x)))
246+
247+
# Filter out duplicates
248+
no_dup = []
249+
if not sorted_iter:
250+
return no_dup
251+
252+
last_v = sorted_iter[0]
253+
last_key_val = key(last_v)
254+
no_dup.append(last_v)
255+
256+
for v in sorted_iter[1:]:
257+
key_v = key(v)
258+
if order(key_v, last_key_val) != 0:
315259
no_dup.append(v)
260+
last_key_val = key_v
261+
316262
return no_dup
317263

318264

0 commit comments

Comments
 (0)