2 // InternalOrderedSequence.cs
5 // Alejandro Serrano "Serras" (trupill@yahoo.es)
6 // Marek Safar <marek.safar@gmail.com>
8 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Generic;
36 sealed class InternalOrderedSequence<TElement, TKey> : AOrderedEnumerable<TElement>
38 readonly IEnumerable<TElement> source;
39 readonly Func<TElement, TKey> key_selector;
40 readonly IComparer<TKey> comparer;
41 readonly bool descending;
43 internal InternalOrderedSequence (IEnumerable<TElement> source, Func<TElement, TKey> keySelector,
44 IComparer<TKey> comparer, bool descending)
47 this.key_selector = keySelector;
48 this.comparer = comparer ?? Comparer<TKey>.Default;
49 this.descending = descending;
52 public override IEnumerable<TElement> Sort (IEnumerable<TElement> parentSource)
55 return parent.Sort (source);
56 return PerformSort (parentSource);
59 public override IEnumerator<TElement> GetEnumerator ()
61 return PerformSort (source).GetEnumerator ();
64 List<TElement> source_list;
68 IEnumerable<TElement> PerformSort (IEnumerable<TElement> items)
70 // It first enumerates source, collecting all elements
71 source_list = new List<TElement> (items);
73 // If the source contains just zero or one element, there's no need to sort
74 if (source_list.Count <= 1)
77 // Then evaluate the keySelector function for each element,
78 // collecting the key values
79 keys = new TKey [source_list.Count];
80 indexes = new int [source_list.Count];
81 for (int i = 0; i < source_list.Count; i++) {
82 keys [i] = key_selector (source_list [i]);
86 // Then sorts the elements according to the collected
87 // key values and the selected ordering
88 QuickSort(0, indexes.Length - 1);
90 // Return the values as IEnumerable<TElement>
91 TElement[] orderedList = new TElement [indexes.Length];
92 for (int i = 0; i < indexes.Length; i++)
93 orderedList [i] = source_list [indexes [i]];
97 int CompareItems (int firstIndex, int secondIndex)
99 int comparison = comparer.Compare (keys [firstIndex], keys [secondIndex]);
101 // If descending, return the opposite comparison
102 return (descending ? -comparison : comparison);
105 // We look at the first, middle, and last items in the subarray.
106 // Then we put the largest on the right side, the smallest on
107 // the left side, and the median becomes our pivot.
108 int MedianOfThree (int left, int right)
110 int center = (left + right) / 2;
111 if (CompareItems (indexes [center], indexes [left]) < 0)
113 if (CompareItems (indexes [right], indexes [left]) < 0)
115 if (CompareItems (indexes [right], indexes [center]) < 0)
116 Swap (center, right);
117 Swap (center, right - 1);
118 return indexes [right - 1];
121 void QuickSort (int left, int right)
123 if (left + 3 <= right) {
124 int l = left, r = right - 1, pivot = MedianOfThree (left, right);
126 while (CompareItems (indexes [++l], pivot) < 0) {}
127 while (CompareItems (indexes [--r], pivot) > 0) {}
135 // Partition and sort
136 QuickSort (left, l - 1);
137 QuickSort (l + 1, right);
139 // If there are three items in the subarray, insertion sort is better
140 InsertionSort (left, right);
143 void InsertionSort (int left, int right)
145 for (int i = left + 1; i <= right; i++) {
146 int j, tmp = indexes [i];
147 for (j = i; j > left && CompareItems (tmp, indexes [j - 1]) < 0; j--)
148 indexes [j] = indexes [j - 1];
153 void Swap (int left, int right)
155 int temp = indexes [right];
156 indexes [right] = indexes [left];
157 indexes [left] = temp;