I have a List<TimeAndCode> of objects. Every object contains a Code and a TimeSpan value.
public struct TimeAndCode {
public TimeSpan Time { get; set; }
public string Code { get; set; }
}
The occuring codes are pre defined as "CO", "GO" and "BT".
When the Time property hits the same value, the order of the list needs to be in a certan format. e.g. (JSON representation for readability)
[
{"Time" : "08:00:00", "Code" : "CO" },
{"Time" : "09:00:00", "Code" : "GO" },
{"Time" : "09:30:00", "Code" : "CO" },
{"Time" : "09:30:00", "Code" : "GO" },
{"Time" : "09:30:00", "Code" : "CO" },
{"Time" : "09:30:00", "Code" : "GO" },
{"Time" : "09:30:00", "Code" : "BT" },
{"Time" : "12:30:00", "Code" : "CO" },
{"Time" : "12:30:00", "Code" : "GO" },
{"Time" : "13:30:00", "Code" : "CO" },
{"Time" : "13:30:00", "Code" : "GO" },
{"Time" : "13:30:00", "Code" : "BT" },
{"Time" : "13:30:00", "Code" : "CO" },
{"Time" : "13:30:00", "Code" : "GO" }
]
So the pattern is either CO -> GO or GO -> BT or CO -> GO -> BT -> CO -> GO.
There might be a good old if else solution, but I'm looking for a nice and easy to use LINQ solution. (e.g. list.OrderBy( x => x.Time ).RearrangeBy( x => x.Code, pattern ); )
EDIT
The custom ordering must only take place, when the codes are in the same time slot.
The easiest pattern is:
CO -> GO -> CO -> GO -> CO -> GO
But there is also a possibility that a BT can be present:
CO -> GO -> BT -> CO -> GO -> BT -> CO -> GO -> BT -> CO
But there is also a possibility that there is only one BT:
CO -> GO -> BT -> GO -> GO -> CO -> GO -> CO -> GO
CO -> GO -> CO -> GO -> BT -> CO -> GO -> CO -> GO
CO -> GO -> CO -> GO -> CO -> GO -> BT -> CO -> GO
CO -> GO -> BT -> CO -> GO -> CO -> GO -> BT -> CO -> GO
So tha major pattern is CO -> GO -> BT.
EDIT 2 Solved
I created an extension method. May be this code is useful for somebody. (room for improvement)
public static IEnumerable<TSource> RearrangeByPattern<TSource, TKey>(this IEnumerable<TSource> list, Func<TSource, TKey> keySelector, IEnumerable<TKey> pattern)
{
var groups = list.GroupBy(keySelector).OrderBy(x => pattern.IndexOf(x.Key));
var maxOccurences = groups.Select(x => x.Count()).Max();
var result = new List<TSource>();
for (var i = 0; i < maxOccurences; i++)
{
foreach (var group in groups)
{
if (group.Count() > i)
{
result.Add(group.ElementAt(i));
}
}
}
return result;
}
Now I can use it like this:
var list = new List<TimeAndCode>();
... // add values
var ordered = list.OrderBy(x => x.Date).RearrangeByPattern( x => x.Code, new string[] { "CO", "GO", "BT" });