需要有关如何在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查询的建议顺序对其进行排序的任何建议。
答案 0 :(得分:1)
这是我的目标。首先将字符串分成多个部分,例如2.11a(ii)
将变为2
,11
,a
和ii
。前两个部分可以解析为正整数。第二部分使用a=1
,b=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
,因此我们可以在这些项目的列表上使用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...");
}
输出