Here is a method for sorting arrays composed by consecutive triplets, that should be quite efficient. Each sorting operation allocates an auxiliary int[] indices
array, having a third of the size of the source array. The sorting is performed on this auxiliary array, reducing the swap operations on the larger source array to the absolute minimum (at most N - 1 swaps).
public static void SortTriplets<T>(T[] source, Comparison<(T, T, T)> comparison)
{
// Create an array of incremental indices (zero based)
var indices = new int[source.Length / 3];
for (int i = 0; i < indices.Length; i++) indices[i] = i;
// Sort the indices according to the source array and the comparison delegate
Array.Sort<int>(indices, (a, b) =>
{
a *= 3;
b *= 3;
return comparison(
(source[a], source[a + 1], source[a + 2]),
(source[b], source[b + 1], source[b + 2]));
});
// Rearrange the source array according to the sorted indices
for (int i = 0; i < indices.Length - 1; i++)
{
int k = indices[i];
while (k < i) k = indices[k];
if (k == i) continue;
Swap(i, k);
}
void Swap(int a, int b)
{
a *= 3;
b *= 3;
(T, T, T) temp = (source[a], source[a + 1], source[a + 2]);
source[a] = source[b];
source[a + 1] = source[b + 1];
source[a + 2] = source[b + 2];
source[b] = temp.Item1;
source[b + 1] = temp.Item2;
source[b + 2] = temp.Item3;
}
}
Usage example:
var random = new Random();
int[] source = Enumerable.Range(1, 15).Select(_ => random.Next(1, 6)).ToArray();
Console.WriteLine($"Source: {String.Join(", ", source)}");
SortTriplets(source, (a, b) =>
{
int ret = Comparer<int>.Default.Compare(a.Item1, b.Item1);
if (ret == 0) ret = Comparer<int>.Default.Compare(a.Item2, b.Item2);
return ret;
});
Console.WriteLine($"Sorted: {String.Join(", ", source)}");
Output:
Source: 3, 2, 3, 2, 2, 1, 2, 3, 2, 5, 4, 2, 1, 5, 4
Sorted: 1, 5, 4, 2, 2, 1, 2, 3, 2, 3, 2, 3, 5, 4, 2
Try it on Fiddle.