Ну, у pswg отличный ответ, но так как я немного поработал над этим, я решил, что я также опубликую свою.
Мое предложение состоит в том, чтобы создать класс, который инкапсулирует данные из строки, экземпляры которых могут быть созданы только статическим методом Parse
.Этот Parse
метод принимает строку и затем анализирует ее, устанавливая свойства класса, как он делает, и затем возвращает экземпляр класса.
Класс также реализует IComparable
, поэтому мы можемиспользуйте методы Sort
и OrderBy
в списке этих элементов.
Я также использовал тот же ответ для разбора римских чисел, который был использован выше (это первый результат при поиске «средства сравнения римских чисел»)).
Вот класс:
public class BandLevelComponent : IComparable<BandLevelComponent>
{
public int Major { get; private set; }
public int Minor { get; private set; }
public string Revision { get; private set; }
public string RomanNumeral { get; private set; }
private static Dictionary<char, int> _romanMap = new Dictionary<char, int>
{
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000}
};
private BandLevelComponent()
{
}
public static BandLevelComponent Parse(string input)
{
if (string.IsNullOrWhiteSpace(input)) return null;
BandLevelComponent result = new BandLevelComponent();
int temp;
var parts = input.Split('.');
int.TryParse(parts[0], out temp);
result.Major = temp;
if (parts.Length > 1)
{
var minor = string.Concat(parts[1].TakeWhile(char.IsNumber));
int.TryParse(minor, out temp);
result.Minor = temp;
if (parts[1].Length > minor.Length)
{
var remaining = parts[1].Substring(minor.Length);
var openParen = remaining.IndexOf("(");
if (openParen > 0) result.Revision = remaining.Substring(0, openParen);
if (openParen > -1)
result.RomanNumeral = remaining
.Split(new[] {'(', ')'}, StringSplitOptions.RemoveEmptyEntries)
.Last();
}
}
return result;
}
public int CompareTo(BandLevelComponent other)
{
if (other == null) return 1;
if (Major != other.Major) return Major.CompareTo(other.Major);
if (Minor != other.Minor) return Minor.CompareTo(other.Minor);
if (Revision != other.Revision) return Revision.CompareTo(other.Revision);
return RomanNumeral != other.RomanNumeral
? RomanToInteger(RomanNumeral).CompareTo(RomanToInteger(other.RomanNumeral))
: 0;
}
public override string ToString()
{
var revision = Revision ?? "";
var roman = RomanNumeral == null ? "" : $"({RomanNumeral})";
return $"{Major}.{Minor}{revision}{roman}";
}
private static int RomanToInteger(string romanNumeral)
{
var roman = romanNumeral?.ToUpper();
var number = 0;
for (var i = 0; i < roman?.Length; i++)
{
if (i + 1 < roman.Length && _romanMap[roman[i]] < _romanMap[roman[i + 1]])
{
number -= _romanMap[roman[i]];
}
else
{
number += _romanMap[roman[i]];
}
}
return number;
}
}
А вот пример использования:
private static void Main()
{
var dbStrings = new[]
{
"1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11",
"1.12", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18", "1.19", "1.20", "2.1a(i)",
"2.1a(ii)", "2.1a(iii)", "2.1a(iv)", "2.1a(v)", "2.1a(vi)", "2.1a(vii)"
};
// Custom extension method for shuffling
dbStrings.Shuffle();
// Select each string into our custom class
var bandLevels = dbStrings.Select(BandLevelComponent.Parse).ToList();
Console.WriteLine("\nShuffled List");
Console.WriteLine(string.Join(", ", bandLevels));
// Sort the list
bandLevels.Sort();
Console.WriteLine("\nSorted List");
Console.WriteLine(string.Join(", ", bandLevels));
// Order the list descending (largest first)
bandLevels = bandLevels.OrderByDescending(b => b).ToList();
Console.WriteLine("\nOrderByDescending List");
Console.WriteLine(string.Join(", ", bandLevels));
GetKeyFromUser("\nDone! Press any key to exit...");
}
Вывод