|
namespace SimpleConsole |
|
{ |
|
using System; |
|
using System.Collections.Generic; |
|
|
|
public class ArraySorter<TElement> |
|
{ |
|
private OrderCriteria<TElement> m_headCriteria; |
|
private OrderCriteria<TElement> m_tailCriteria; |
|
|
|
public ArraySorter<TElement> OrderBy<TKey>(Func<TElement, TKey> keySelector) |
|
{ |
|
return this.OrderBy(keySelector, null, false); |
|
} |
|
|
|
public ArraySorter<TElement> OrderBy<TKey>( |
|
Func<TElement, TKey> keySelector, IComparer<TKey> keyComparer, bool descending) |
|
{ |
|
var newCriteria = new OrderCriteria<TElement, TKey>( |
|
keySelector, keyComparer, descending); |
|
|
|
if (this.m_headCriteria == null) |
|
{ |
|
this.m_headCriteria = this.m_tailCriteria = newCriteria; |
|
} |
|
else |
|
{ |
|
this.m_tailCriteria.NextCriteria = newCriteria; |
|
this.m_tailCriteria = newCriteria; |
|
} |
|
|
|
return this; |
|
} |
|
|
|
public void Sort(TElement[] array) |
|
{ |
|
if (this.m_headCriteria == null) return; |
|
var indexComparer = this.m_headCriteria.CreateComparer(array); |
|
|
|
var indexArray = new int[array.Length]; |
|
for (int i = 0; i < array.Length; i++) indexArray[i] = i; |
|
|
|
//Array.Sort(indexArray, array, indexComparer); |
|
|
|
Array.Sort(indexArray, indexComparer); |
|
|
|
var arrayCopy = new TElement[array.Length]; |
|
Array.Copy(array, arrayCopy, array.Length); |
|
|
|
for (int i = 0; i < array.Length; i++) |
|
{ |
|
array[i] = arrayCopy[indexArray[i]]; |
|
} |
|
} |
|
} |
|
|
|
internal abstract class OrderCriteria<TElement> |
|
{ |
|
public abstract IComparer<int> CreateComparer(TElement[] array); |
|
|
|
public OrderCriteria<TElement> NextCriteria; |
|
} |
|
|
|
internal class OrderCriteria<TElement, TKey> : OrderCriteria<TElement> |
|
{ |
|
private IComparer<TKey> m_keyComparer; |
|
private Func<TElement, TKey> m_keySelector; |
|
private bool m_descending; |
|
|
|
public OrderCriteria( |
|
Func<TElement, TKey> keySelector, IComparer<TKey> keyComparer, bool decesnding) |
|
{ |
|
this.m_keySelector = keySelector; |
|
this.m_keyComparer = keyComparer; |
|
this.m_descending = decesnding; |
|
} |
|
|
|
public override IComparer<int> CreateComparer(TElement[] array) |
|
{ |
|
var keyArray = new TKey[array.Length]; |
|
for (int i = 0; i < array.Length; i++) |
|
{ |
|
keyArray[i] = this.m_keySelector(array[i]); |
|
} |
|
|
|
var comparer = new IndexComparer<TKey>(keyArray, this.m_keyComparer, this.m_descending); |
|
if (this.NextCriteria != null) |
|
{ |
|
comparer.NextIndexComparer = this.NextCriteria.CreateComparer(array); |
|
} |
|
|
|
return comparer; |
|
} |
|
} |
|
|
|
internal class IndexComparer<TKey> : IComparer<int> |
|
{ |
|
public IComparer<int> NextIndexComparer; |
|
|
|
private TKey[] m_keyArray; |
|
private IComparer<TKey> m_keyComparer; |
|
private bool m_decesnding; |
|
|
|
public IndexComparer(TKey[] keyArray, IComparer<TKey> keyComparer, bool decesnding) |
|
{ |
|
this.m_keyArray = keyArray; |
|
this.m_keyComparer = keyComparer ?? Comparer<TKey>.Default; |
|
this.m_decesnding = decesnding; |
|
} |
|
|
|
public int Compare(int indexX, int indexY) |
|
{ |
|
var keyX = this.m_keyArray[indexX]; |
|
var keyY = this.m_keyArray[indexY]; |
|
|
|
var result = this.m_keyComparer.Compare(keyX, keyY); |
|
|
|
if (result == 0) |
|
{ |
|
return this.NextIndexComparer == null ? 0 : |
|
this.NextIndexComparer.Compare(indexX, indexY); |
|
} |
|
else |
|
{ |
|
return this.m_decesnding ? -result : result; |
|
} |
|
} |
|
} |
|
} |