[Checkins] SVN: Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py Found a way to support differing sort ordering without code complexity explosion

Hano Schlichting cvs-admin at zope.org
Mon Mar 26 21:14:44 UTC 2012


Log message for revision 124746:
  Found a way to support differing sort ordering without code complexity explosion
  

Changed:
  U   Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py

-=-
Modified: Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py
===================================================================
--- Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py	2012-03-26 21:10:59 UTC (rev 124745)
+++ Products.ZCatalog/trunk/src/Products/ZCatalog/Catalog.py	2012-03-26 21:14:41 UTC (rev 124746)
@@ -16,6 +16,7 @@
 import warnings
 from bisect import bisect
 from collections import defaultdict
+from operator import itemgetter
 from random import randint
 
 import Acquisition
@@ -714,6 +715,9 @@
                 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,
@@ -749,18 +753,13 @@
                             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]
@@ -776,10 +775,7 @@
                     # 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,
@@ -817,7 +813,7 @@
                         n += 1
                     worst = keys[0]
             if index2 is not None:
-                result.sort(reverse=True)
+                result = multisort(result, sort_spec)
             else:
                 result.reverse()
             if merge:
@@ -854,7 +850,7 @@
                         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)
@@ -1016,3 +1012,25 @@
         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)



More information about the checkins mailing list