我有List<MyObject>
...
MyObject有一个名为 LineId (整数)...
所以,我需要在列表中单独连接所有LineId ...
示例:
List<MyObject> :
LineId =1
LineId =1
LineId =1
LineId =2
LineId =1
LineId =2
结果必须是4个单独列表:
LineId =1
LineId =1
LineId =1
-------------
LineId =2
-------------
LineId =1
-------------
LineId =2
所以,我必须将所有连续的LineId分开......
使用Linq有一种简单的方法吗?
由于
答案 0 :(得分:3)
List<MyObject> currentList = new List<MyObject>();
List<List<MyObject>> finalList = new List<List<MyObject>>();
for (int i = 0; i < myObjects.Count; i++)
{
//If the list is empty, or has the same LineId, add to it.
if (currentList.Count == 0 || currentList[0].LineId == myObjects[i].LineId)
{
currentList.Add(myObjects[i]);
}
//Otherwise, create a new list.
else
{
finalList.Add(currentList);
currentList = new List<MyObject>();
currentList.Add(myObjects[i]);
}
}
finalList.Add(currentList);
我知道你要求linq,但我认为这可能是一个更好的解决方案。
答案 1 :(得分:3)
为了更好的衡量,LINQ解决方案如何使用LINQ实现:
public static IEnumerable<IEnumerable<TSource>> GroupConsecutive<TSource,TKey>(
this IEnumerable<TSource> source, Func<TSource,TKey> keySelector) {
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
var comparer = EqualityComparer<TKey>.Default;
var grouped = new List<TSource>();
using (var iter = source.GetEnumerator()) {
if (!iter.MoveNext()) yield break;
grouped.Add(iter.Current);
var last = iter.Current;
while (iter.MoveNext()) {
if (!comparer.Equals(keySelector(iter.Current), keySelector(last))) {
yield return grouped.AsReadOnly();
grouped = new List<TSource>();
}
grouped.Add(iter.Current);
last = iter.Current;
}
yield return grouped.AsReadOnly();
}
}
答案 2 :(得分:2)
这看起来很难看,但这个想法很明确,我觉得它很有效:
var agg = list.Aggregate(
new List<List<Line>>(),
(groupedLines, line) => {
if (!groupedLines.Any()) {
groupedLines.Add(new List<Line>() { line });
}
else {
List<Line> last = groupedLines.Last();
if (last.First().LineId == line.LineId) {
last.Add(line);
}
else {
List<Line> newGroup = new List<Line>();
newGroup.Add(line);
groupedLines.Add(newGroup);
}
}
return groupedLines;
}
);
我假设你有:
class Line { public int LineId { get; set; } }
和
List<Line> list = new List<Line>() {
new Line { LineId = 1 },
new Line { LineId = 1 },
new Line { LineId = 1 },
new Line { LineId = 2 },
new Line { LineId = 1 },
new Line { LineId = 2 }
};
现在如果我执行
foreach(var lineGroup in agg) {
Console.WriteLine(
"Found {0} consecutive lines with LineId = {1}",
lineGroup.Count,
lineGroup.First().LineId
);
foreach(var line in lineGroup) {
Console.WriteLine("LineId = {0}", line.LineId);
}
}
我明白了:
Found 3 consecutive lines with LineId = 1
LineId = 1
LineId = 1
LineId = 1
Found 1 consecutive lines with LineId = 2
LineId = 2
Found 1 consecutive lines with LineId = 1
LineId = 1
Found 1 consecutive lines with LineId = 2
LineId = 2
打印在控制台上。
答案 3 :(得分:2)
稍微小一点的解决方案,但可能(读:绝对)不太清楚:
var lst = new [] {
new { LineID = 1 },
new { LineID = 1 },
new { LineID = 1 },
new { LineID = 2 },
new { LineID = 1 },
new { LineID = 2 },
};
var q = lst
.Select((x,i) => new {Item = x, Index = i})
.GroupBy(x => x.Item)
.SelectMany(x => x.Select((y,i) => new { Item = y.Item, Index = y.Index, Sort = i - y.Index }))
.OrderBy(x => x.Index)
.GroupBy(x => x.Sort)
.Select(x => x.Select(y => y.Item));
返回IEnumerable<IEnumerable<int>>
:
1,1,1
2
1
2
注意,如果您不关心订单,可以删除匿名对象中的“OrderBy”行和“Index = y.Index”属性,它将返回:
1,1,1
1
2
2
答案 4 :(得分:1)
这是一个解决方案,其中行按每个连续子序列中最后一项的索引进行分组。
在您的示例中,这些是边界索引:
LineId Index Boundary Index
1 0 2
1 1 2
1 2 2
2 3 3
1 4 4
2 5 5
以下是Linq查询:
var lines = new List<MyObject>
{
new MyObject { LineId = 1 },
new MyObject { LineId = 1 },
new MyObject { LineId = 1 },
new MyObject { LineId = 2 },
new MyObject { LineId = 1 },
new MyObject { LineId = 2 },
};
IEnumerable<List<int>> consecutiveLineIds = lines
.Select((line, i) => new
{
Line = line,
Boundary = i + lines.Skip(i)
.TakeWhile(l => l.LineId == line.LineId).Count() - 1
})
.GroupBy(item => item.Boundary, item => item.Line.LineId)
.Select(g => g.ToList());
答案 5 :(得分:0)
void Main()
{
var list = new []{
new { LineId = 1 },
new { LineId = 1 },
new { LineId = 1 },
new { LineId = 2 },
new { LineId = 2 },
new { LineId = 1 },
new { LineId = 1 },
new { LineId = 3 },
new { LineId = 3 },
new { LineId = 1 }
};
var groups =
from i in list
group i by i.LineId into g
select new { LineId = g.Key, MyObject = g };
}