这是我的问题,我有一个查询结果集,如下所示:
id_1 - 0 - datetime - gps coordinates
id_2 - 0 - datetime - gps coordinates
id_3 - 1 - datetime - gps coordinates
id_4 - 1 - datetime - gps coordinates
id_5 - 1 - datetime - gps coordinates
id_6 - 1 - datetime - gps coordinates
id_7 - 0 - datetime - gps coordinates
id_8 - 0 - datetime - gps coordinates
id_9 - 0 - datetime - gps coordinates
id_10 - 0 - datetime - gps coordinates
id_11 - 1 - datetime - gps coordinates
id_12 - 1 - datetime - gps coordinates
id_13 - 0 - datetime - gps coordinates
id_14 - 0 - datetime - gps coordinates
这显然会返回一个列表,但是我想将第二列中值为1的集合保存在列表列表中,其中每组列表都是以前具有0的列表。 看起来像这样:
List1: [id_3], [...] , [id_6]
List2: [id_11], [...], [id_12]
我不知道0或1的元素数量,因此在这种意义上必须是通用的
我正在使用C#4.5,并且正在考虑使用Linq来实现此目的,而不是老式的foreach。
有人能指出我正确的方向吗?
答案 0 :(得分:2)
我认为框架中没有内置的东西,但是您可以为其创建扩展方法:
public static class LinqHelper
{
public static IEnumerable<List<Item>> Partition(this IEnumerable<Item> source, Func<Item, bool> selector)
{
List<Item> currentList = new List<Item>();
foreach (var item in source)
{
if (selector(item))
{
currentList.Add(item);
}
else if (currentList.Count != 0)
{
yield return currentList;
currentList = new List<Item>();
}
}
if (currentList.Count != 0)
{
yield return currentList;
}
}
}
public class Item
{
public int Id { get; set; }
public int Val { get; set; }
}
void Main()
{
var list = new List<Item>(){
new Item{ Id = 1, Val = 0 },
new Item{ Id = 2, Val = 0 },
new Item{ Id = 3, Val = 1 },
new Item{ Id = 4, Val = 1 },
new Item{ Id = 5, Val = 1 },
new Item{ Id = 6, Val = 1 },
new Item{ Id = 7, Val = 0 },
new Item{ Id = 8, Val = 0 },
new Item{ Id = 9, Val = 0 },
new Item{ Id = 10, Val = 0 },
new Item{ Id = 11, Val = 1 },
new Item{ Id = 12, Val = 1 },
new Item{ Id = 13, Val = 0 },
new Item{ Id = 14, Val = 0 },
};
var result = list.Partition(i => i.Val == 1).Where(i => true).ToList();
}
答案 1 :(得分:2)
如果您希望避免使用foreach,可以使用LINQ的Aggregate扩展名来实现。
提供以下课程:
public class SomeType
{
public int Id {get;set;}
public int Val {get;set;}
}
并已生成以下项目:
var items = new List<SomeType>();
for(var i = 1; i <= 14; i++)
{
var val = 0;
if((3 <= i && i <= 6) || (11 <= i && i <= 12))
val = 1;
items.Add(new SomeType { Id = i, Val = val});
}
您可以像这样获得值为1的项目列表:
var grouped = items.Aggregate(new List<List<SomeType>>() { new List<SomeType>() },
(acc,elem) =>
{
if(elem.Val == 0 && acc.Last().Count != 0)
acc.Add(new List<SomeType>());
else if(elem.Val == 1)
acc.Last().Add(elem);
return acc;
}, acc => acc.Where(x => x.Count != 0));
int groupNum = 1;
foreach (var group in grouped)
{
Console.WriteLine($"Group {groupNum++}");
foreach (var item in group)
Console.WriteLine($"{item.Id} - {item.Val}");
}
/* output:
Group 1
3 - 1
4 - 1
5 - 1
6 - 1
Group 2
11 - 1
12 - 1
*/
这假定可以在出现0值之前添加具有1值的条目,而且我不确定这比使用foreach更易读,并且实现一个扩展方法可能会更好无论如何都可能会使用foreach。
答案 2 :(得分:0)
var prev = 0;
List<int> bag = null;
var result = new List<List<int>>();
foreach(var item in list)
{
if(item.Val == 1)
{
if(prev == 0)
{
if(bag != null)
result.Add(bag);
bag = new List<int>();
}
bag.Add(item.Id);
}
prev = item.Val;
}
if(bag != null)
result.Add(bag);
result.ForEach(x => {
Console.WriteLine(String.Join(", ", x));
});
//3, 4, 5, 6
//11, 12