1. Array.Sort<TKey, TValue>(keys, value)
method
If your lists are actually System.Array
s or you do not care about few additional copying due to ToArray
calls, then the simplest way is to use the Array.Sort<TKey, TValue>(keys, value)
method
public static IList<Double> GetKeys()
{
return new Double[]
{
0.2,
0.6,
0.9,
10.58,
-1.54,
6.5
};
}
public static IList<Double> GetValues()
{
return new Double[]
{
5.4,
4.1,
6.7,
45.7,
-7.02,
6.66
};
}
public static void Print<T>(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
foreach (var item in items)
{
Console.WriteLine(item);
}
}
public static void PrintKeyValues<TKey, TValue>(IEnumerable<TKey> keys, IEnumerable<TValue> values)
{
if (keys == null)
throw new ArgumentNullException("keys");
if (values == null)
throw new ArgumentNullException("values");
var pairs = keys
.Zip(values,
(key, value) =>
String.Format("[{0}] = {1}", key, value));
Print(pairs);
}
static void Main(string[] args)
{
var keys = GetKeys();
var values = GetValues();
Console.WriteLine("Before");
PrintKeyValues(keys, values);
Console.WriteLine();
Console.WriteLine("After");
var keysArray = keys.ToArray();
var valuesArray = values.ToArray();
Array.Sort(keysArray, valuesArray);
PrintKeyValues(keysArray, valuesArray);
Console.ReadKey();
}
2. Nearly pure LINQ
If you need LINQ solution, then you obviously have no problems with excessive copying. So, you have to sort one array, while preserving the indices with How to get index using LINQ? and then shuffle the associated array:
public static T[] ShuffleFromIndices<T>(this IList<T> items, IList<Int32> indices)
{
if (items == null)
throw new ArgumentNullException("items");
if (indices == null)
throw new ArgumentNullException("indices");
if (items.Count != indices.Count)
throw new ArgumentException("items and indices have different lengths");
T[] result = new T[items.Count];
for (int i = 0; i < items.Count; i++)
{
var shuffleIndex = indices[i];
result[i] = items[shuffleIndex];
}
return result;
}
public static Tuple<TKey[], TValue[]> SortNotInPlace<TKey, TValue>(IList<TKey> keys, IList<TValue> values)
{
if (keys == null)
throw new ArgumentNullException("keys");
if (values == null)
throw new ArgumentNullException("values");
if (keys.Count != values.Count)
throw new ArgumentException("Keys and values have different lengths");
var sortedKeysWithIndices = keys
.Select((key, index) =>
new { key, index })
.OrderBy(keyIndex => keyIndex.key);
var shuffleIndices = sortedKeysWithIndices
.Select(keyIndex => keyIndex.index)
.ToArray();
var sortedValues = values.ShuffleFromIndices(shuffleIndices);
var sortedKeys = sortedKeysWithIndices
.Select(keyIndex => keyIndex.key)
.ToArray();
return new Tuple<TKey[], TValue[]>(sortedKeys,
sortedValues);
}
static void Main(string[] args)
{
var keys = GetKeys();
var values = GetValues();
Console.WriteLine("Before");
PrintKeyValues(keys, values);
Console.WriteLine();
Console.WriteLine("With LINQ");
var sorted = SortNotInPlace(keys, values);
var sortedKeys = sorted.Item1;
var sortedValues = sorted.Item2;
PrintKeyValues(sortedKeys, sortedValues);
Console.ReadKey();
}
3. High performance
If you really care about performance and need no-additional-memory in-place sorting, then you will have to implement your own Sort
method, that synchronously sorts both lists.