我对LINQ
相对较新,目前正致力于一项结合分组和排序的查询。我将从这里开始一个例子。基本上我有一个任意的数字序列表示为字符串:
List<string> sNumbers = new List<string> {"34521", "38450", "138477", "38451", "28384", "13841", "12345"}
我需要在此列表中找到包含搜索模式的所有sNumbers
(例如“384”)
然后返回过滤后的序列,以便首先排序以搜索模式(“384”)开头的sNumbers
,然后是在某处包含搜索模式的剩余sNumbers
。所以它会是这样的(请注意组中的字母排序):
{"38450", "38451", "13841", "28384", "138477"}
以下是我的开始:
outputlist = (from n in sNumbers
where n.Contains(searchPattern
select n).ToList();
所以现在我们拥有包含搜索模式的所有数字。这就是我被困的地方。我知道在这一点上我需要将结果“分组”成两个序列。一个以搜索模式开始,另一个不是。然后按字母顺序在每个组中应用辅助排序。如何编写一个结合了所有这些的查询?
答案 0 :(得分:3)
我认为你不需要任何分组或列表分割来获得你想要的结果,所以我不会回答关于组合和分组的问题,而是会发布我想做的事情来获得理想的结果:
sNumbers.Where(x=>x.Contains(pattern))
.OrderByDescending(x => x.StartsWith(pattern)) // first criteria
.ThenBy(x=>Convert.ToInt32(x)) //this do the trick instead of GroupBy
.ToList();
答案 1 :(得分:2)
这里的优化版只需要一个LINQ语句:
string match = "384";
List<string> sNumbers = new List<string> {"34521", "38450", "138477", "38451", "28384", "13841", "12345"};
// That's all it is
var result =
(from x in sNumbers
group x by new { Start = x.StartsWith(match), Contain = x.Contains(match)}
into g
where g.Key.Start || g.Key.Contain
orderby !g.Key.Start
select g.OrderBy(Convert.ToInt32)).SelectMany(x => x);
result.ToList().ForEach(x => Console.Write(x + " "));
步骤:
1。)根据StartsWith和Contains分组到 g 组
2。)只需选择包含匹配的组
3。)通过StartsWith键的反转顺序(以便StartsWith = true在StartsWith = false之前)
4.。)选择两个组的元素的排序列表
5.)在两个列表上执行flatMap(SelectMany)以接收一个最终结果列表
这是一个未经优化的版本:
string match = "384";
List<string> sNumbers = new List<string> {"34521", "38450", "138477", "38451", "28384", "13841", "12345"};
var matching = from x in sNumbers
where x.StartsWith(match)
orderby Convert.ToInt32(x)
select x;
var nonMatching = from x in sNumbers
where !x.StartsWith(match) && x.Contains(match)
orderby Convert.ToInt32(x)
select x;
var result = matching.Concat(nonMatching);
result.ToList().ForEach(x => Console.Write(x + " "));
答案 2 :(得分:2)
var result = sNumbers
.Where(e => e.StartsWith("384"))
.OrderBy(e => Int32.Parse(e))
.Union(sNumbers
.Where(e => e.Contains("384"))
.OrderBy(e => Int32.Parse(e)));
答案 3 :(得分:2)
这似乎相当直接,除非我误解了一些事情:
List<string> outputlist =
sNumbers
.Where(n => n.Contains("384"))
.OrderBy(n => int.Parse(n))
.OrderByDescending(n => n.StartsWith("384"))
.ToList();
我明白了:
答案 4 :(得分:0)
Linq有一个OrderBy方法,允许您提供一个自定义类来决定应该如何排序。看这里:https://msdn.microsoft.com/en-us/library/bb549422(v=vs.100).aspx
然后你可以编写你的IComparer类,它在构造函数中取值,然后是一个比较方法,它更喜欢以该值开头的值。
这样的事情可能是:
public class CompareStringsWithPreference : IComparer<string> {
private _valueToPrefer;
public CompareStringsWithPreference(string valueToPrefer) {
_valueToPrefer = valueToPrefer;
}
public int Compare(string s1, string s2) {
if ((s1.StartsWith(_valueToPrefer) && s2.StartsWith(_valueToPrefer)) ||
(!s1.StartsWith(_valueToPrefer) && !s2.StartsWith(_valueToPrefer)))
return string.Compare(s1, s2, true);
if (s1.StartsWith(_valueToPrefer)) return -1;
if (s2.StartsWith(_valueToPrefer)) return 1;
}
}
然后像这样使用它:
outputlist = (from n in sNumbers
where n.Contains(searchPattern)
select n).OrderBy(n, new CompareStringsWithPreference(searchPattern))ToList();
答案 5 :(得分:0)
您可以创建一个列表,其中的字符串以searchPattern
变量开头,另一个包含searchPattern
,但不是以({以避免重复两个列表中的元素重复):
string searchPattern = "384";
List<string> sNumbers = new List<string> { "34521", "38450", "138477", "38451", "28384", "13841", "12345" };
var list1 = sNumbers.Where(s => s.StartsWith(searchPattern)).OrderBy(s => s).ToList();
var list2 = sNumbers.Where(s => !s.StartsWith(searchPattern) && s.Contains(searchPattern)).OrderBy(s => s).ToList();
var outputList = new List<string>();
outputList.AddRange(list1);
outputList.AddRange(list2);
答案 6 :(得分:0)
对不起家伙,在阅读完回复后,我意识到我在我的问题中犯了一个错误。正确答案如下:(排序方式为&#34;以&#34开头;首先排序,然后按字母顺序排列(非数字排列)
//输出:{&#34; 38450&#34;,&#34; 38451&#34;,&#34; 13841&#34;,&#34; 138477&#34;,&#34; 28384&# 34;}
我能够通过以下查询实现这一目标:
string searchPattern = "384";
List<string> result =
sNumbers
.Where(n => n.Contains(searchpattern))
.OrderBy(s => !s.StartsWith(searchpattern))
.ThenBy(s => s)
.ToList();
由于