Порядок запросов Linq для строки - PullRequest
0 голосов
/ 19 февраля 2019

Нужны предложения о том, как упорядочить строки в порядке в запросе linq.

Пример строк в дБ [1,1 1,2 1,3 1,4 1,5 1,6 1,7 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,202.1a (i) 2.1a (ii) 2.1a (iii) 2.1a (iv) 2.1a (v) 2.1a (vi) 2.1a (vii), ....]

Чтобырешить вопрос для рабочего случая.

Я написал запрос linq, в котором предполагается упорядочить задания на основе уровня полосы

var GetOrder =(from a in db.Details

           join b in db.Information on a.InfromationId equals b.Id

           where c.JobId == JobId

           select new {a.Name, a.LastName, b.BandLevel}

           //.OrderBy(b=>b.BandLevel)

           .ToList();

Я добавил приведенный ниже запрос, чтобы он мог упорядочивать и сортировать строки.

GetOrder.Sort((a, b) => a.BandLevel.CompareTo(b.BandLevel));

Предполагается, что этот запрос сортирует строки по порядку, но он не может быть установлен для некоторых строк.

Вместо этого он упорядочивает в этом формате, используя приведенный выше запрос.

1.1, 1.10, 1.19, 1.2, 2.1a (i), 2.21 (v)

Должен быть в этом желаемом списке.

1.1, 1.2, 1.10, 1.19, 2.1a (i), 2.21 (v)

Любые предложения о том, как отсортировать их в предлагаемом порядке для запросов linq.

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Ну, у 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...");
}

Вывод

enter image description here

0 голосов
/ 19 февраля 2019

Вот мой удар.Сначала разбейте строку на несколько частей, например, 2.11a(ii) станет 2, 11, a и ii.Первые две части могут быть проанализированы как обычные целые числа.Вторая часть анализируется как целое число с a=1, b=2 и так далее.Третья часть разбирается как римская цифра (я использовал модифицированную версию алгоритма, представленную в в этом ответе ).Вы собираете эти части как массив целых чисел (я называю их индексами) и сравниваете массив от одного элемента к следующему так, что, если первый индекс каждого равен, элементы равны, и так далее, пока индекс не станет неравным.

public static int CustomComparison(string x, string y)
{
    var xIndexes = StringToIndexes(x);
    var yIndexes = StringToIndexes(y);

    for (int i = 0; i < 4; i++)
    {
        if (xIndexes[i] < yIndexes[i])
        {
            return -1;
        }
        if (xIndexes[i] > yIndexes[i])
        {
            return 1;
        }
    }

    return 0;
}

private static int[] StringToIndexes(string input) {
    var match = Regex.Match(input, @"^(\d+)\.(\d+)([a-z]+)?(?:\(([ivx]+)\))?$");
    if (!match.Success)
    {
        return new[] { 0, 0, 0, 0 };
    }
    return new[] {
        int.Parse(match.Groups[1].Value),
        int.Parse(match.Groups[2].Value),
        AlphabeticToInteger(match.Groups[3].Value),
        RomanToInteger(match.Groups[4].Value),
    };
}

private static int AlphabeticToInteger(string alpha)
{
    return alpha.Aggregate(0, (n, c) => n * 26 + (int)(c - 'a' + 1));
}

private static Dictionary<char, int> RomanMap = new Dictionary<char, int>()
    {
        {'i', 1},
        {'v', 5},
        {'x', 10},
    };

public static int RomanToInteger(string roman)
{
    int number = 0;
    for (int 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...