Here are a couple of ways to pull this off with LINQ, while also correctly sorting the values should they occur in an order other than the one you've presented. For example, if "(avg) Zeta" occurs before "Zeta" then the latter should still come first once sorted.
Here's the sample list, reordered to match what I described above:
var myUnsortedList = new List<string>
{
"Alpha",
"(avg) Alpha",
"(avg) Zeta",
"Zeta",
"Beta",
"(avg) Beta"
};
Lambda syntax
string prefix = "(avg)";
var result = myUnsortedList.Select(s => new
{
Value = s,
Modified = s.Replace(prefix, "").TrimStart(),
HasPrefix = s.StartsWith(prefix)
})
.OrderByDescending(o => o.Modified)
.ThenBy(o => o.HasPrefix)
.Select(o => o.Value);
Zip / Aggregate
string prefix = "(avg)";
var avg = myUnsortedList.Where(o => o.StartsWith(prefix))
.OrderByDescending(o => o);
var regular = myUnsortedList.Where(o => !o.StartsWith(prefix))
.OrderByDescending(o => o);
var result = regular.Zip(avg, (f, s) => new { First = f, Second = s })
.Aggregate(new List<string>(), (list, o) =>
new List<string>(list) { o.First, o.Second });
Query syntax and string splitting
This one is similar to the lambda syntax, except I'm not using the prefix to determine which string has a prefix. Instead, I am splitting on a space, and if the split result has more than one item then I'm assuming that it has a prefix. Next, I order based on the value and the prefix's availability.
var result = from s in myUnsortedList
let split = s.Split(' ')
let hasPrefix = split.Length > 1
let value = hasPrefix ? split[1] : s
orderby value descending, hasPrefix
select s;