简体   繁体   English

Linq查询顺序为字符串

[英]Linq query order by for string

Need suggestions on how to order the strings in order in a linq query. 需要有关如何在linq查询中对字符串进行排序的建议。

Example of strings in db [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) , ....] db中的字符串示例[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),....]

In order to solve the issue for a job case. 为了解决一个工作案例的问题。

I have written a linq query which suppose to order the jobs based on band level 我写了一个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();

I added the below query for it can order and sort for strings. 我添加了以下查询,因为它可以对字符串进行排序和排序。

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

This query is suppose to sort the stings in order but it fails to set for some strings. 该查询假定按顺序对字符串进行排序,但是无法为某些字符串设置字符串。

Instead it orders in this format using the above query. 而是使用上面的查询以这种格式订购。

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

It should be in this desired list . 它应该在此所需的列表中。

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

Any suggestions on how to sort it in the suggested order for linq queries. 关于如何按linq查询的建议顺序对其进行排序的任何建议。

Here's my stab at it. 这是我的目的。 First split the string into various parts, eg 2.11a(ii) will become 2 , 11 , a , and ii . 第一分割字符串成各种部件,例如2.11a(ii)将成为211aii The first two parts can be parsed as regular integers. 前两个部分可以解析为正整数。 The second part is parsed as a integer with a=1 , b=2 and so on. 第二部分被解析为a a=1b=2的整数,依此类推。 The third part is parsed as a Roman numeral (I used a modified version of the algorithm presented in this answer ). 第三部分被解析为罗马数字(我使用了此答案中提出的算法的修改版本)。 You collect these parts as an array of integers (I call them indexes), and compare the array from one item to the next such that if the first index of each is equal, the items are equal, and so on until an index is unequal. 您将这些部分收集为整数数组(我称它们为索引),然后将一项与另一项之间的数组进行比较,以便如果每个项的第一个索引相等,则项相等,依此类推,直到索引不相等。

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;
}

Well, pswg has a great answer, but since I worked on this a little I figured I would post mine as well. 嗯,pswg有一个很好的答案,但是由于我做了一点工作,所以我认为我也将发布它。

My suggestion is to create a class that encapsulates the data from the string, which can only be instantiated from a static Parse method. 我的建议是创建一个封装字符串数据的类,该类只能从静态Parse方法实例化。 This Parse method takes in a string and then parses it, setting the properties of the class as it does, and then returns the instance of the class. Parse方法接收一个字符串,然后对其进行解析,并按其设置类的属性,然后返回该类的实例。

The class also implements IComparable , so we can use the Sort and OrderBy methods on a list of these items. 该类还实现了IComparable ,因此我们可以在这些项目的列表上使用SortOrderBy方法。

I also used the same answer for parsing roman numerals that was used above (it's the first result when searching for "roman numeral comparer"). 我还使用了与上面使用的解析罗马数字相同的答案(这是搜索“罗马数字比较器”时的第一个结果)。

Here's the class: 这是课程:

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;
    }
}

And here's a sample usage: 这是一个示例用法:

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

Output 产量

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM