Linq查询字符串的顺序

时间:2019-02-19 00:23:41

标签: c# asp.net-mvc linq

需要有关如何在linq查询中对字符串进行排序的建议。

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.1 a(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 :(得分:1)

这是我的目标。首先将字符串分成多个部分,例如2.11a(ii)将变为211aii。前两个部分可以解析为正整数。第二部分使用a=1b=2等解析为整数。第三部分被解析为罗马数字(我使用了this answer中提出的算法的修改版本)。您将这些部分收集为整数数组(我称它们为索引),然后将一项与另一项之间的数组进行比较,以便如果每个项的第一个索引相等,则项相等,依此类推,直到索引不相等

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

答案 1 :(得分:1)

好吧,p.s.w.g有一个很好的答案,但是由于我做了一点工作,所以我想我也将发布我的。

我的建议是创建一个封装字符串数据的类,该类只能从静态Parse方法中实例化。此Parse方法接收一个字符串,然后对其进行解析,并按其设置类的属性,然后返回该类的实例。

该类还实现了IComparable,因此我们可以在这些项目的列表上使用SortOrderBy方法。

在解析罗马数字时,我也使用了相同的答案(这是搜索“罗马数字比较器”时的第一个结果)。

这是课程:

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