Skip to content

Commit

Permalink
Found a way to support differing sort ordering without code complexit…
Browse files Browse the repository at this point in the history
…y explosion
  • Loading branch information
hannosch committed Mar 26, 2012
1 parent fd79a2f commit 0977d2a
Showing 1 changed file with 30 additions and 12 deletions.
42 changes: 30 additions & 12 deletions src/Products/ZCatalog/Catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import warnings
from bisect import bisect
from collections import defaultdict
from operator import itemgetter
from random import randint

import Acquisition
Expand Down Expand Up @@ -714,6 +715,9 @@ def sortResults(self, rs, sort_index, reverse=0, limit=None, merge=1,
b_start = rlen - b_end
limit = b_start + b_size

# determine sort_spec
sort_spec = [reverse and -1 or 1, reverse and -1 or 1]

if merge and limit is None and (
rlen > (len(sort_index) * (rlen / 100 + 1))):
# The result set is much larger than the sorted index,
Expand Down Expand Up @@ -749,18 +753,13 @@ def sortResults(self, rs, sort_index, reverse=0, limit=None, merge=1,
append((k2, v2, _self__getitem__))
else:
append((k, intset, _self__getitem__))
# Note that sort keys are unique.

if reverse:
result.sort(reverse=True)
else:
result.sort()
result = multisort(result, sort_spec)
sequence, slen = self._limit_sequence(result, length, b_start,
b_size, switched_reverse)
result = LazyCat(LazyValues(sequence), slen, actual_result_count)
elif limit is None or (limit * 4 > rlen):
# Iterate over the result set getting sort keys from the index
# import pdb; pdb.set_trace()
for did in rs:
try:
key = index_key_map[did]
Expand All @@ -776,10 +775,7 @@ def sortResults(self, rs, sort_index, reverse=0, limit=None, merge=1,
# results with those of other catalogs while avoiding
# the cost of instantiating a LazyMap per result
if merge:
if reverse:
result.sort(reverse=True)
else:
result.sort()
result = multisort(result, sort_spec)
if limit is not None:
result = result[:limit]
sequence, _ = self._limit_sequence(result, 0, b_start, b_size,
Expand Down Expand Up @@ -817,7 +813,7 @@ def sortResults(self, rs, sort_index, reverse=0, limit=None, merge=1,
n += 1
worst = keys[0]
if index2 is not None:
result.sort(reverse=True)
result = multisort(result, sort_spec)
else:
result.reverse()
if merge:
Expand Down Expand Up @@ -854,7 +850,7 @@ def sortResults(self, rs, sort_index, reverse=0, limit=None, merge=1,
n += 1
best = keys[-1]
if index2 is not None:
result.sort()
result = multisort(result, sort_spec)
if merge:
sequence, _ = self._limit_sequence(result, 0, b_start, b_size,
switched_reverse)
Expand Down Expand Up @@ -1016,3 +1012,25 @@ def mergeResults(results, has_sort_keys, reverse):
else:
combined.sort()
return LazyMap(lambda rec: rec[2](rec[1]), combined, len(combined))


def multisort(items, sort_spec):
"""Sort a list by multiple keys bidirectionally.
sort_spec is a list of ones and minus ones, with 1 meaning sort normally
and -1 meaning sort reversed.
The length of sort_spec must match the length of the first value in each
list entry given via `items`.
"""
comparers = []
for i in xrange(len(sort_spec)):
comparers.append((itemgetter(i), sort_spec[i]))

def comparer(left, right):
for func, order in comparers:
result = cmp(func(left), func(right))
if result:
return order * result
return 0
return sorted(items, cmp=comparer)

0 comments on commit 0977d2a

Please sign in to comment.