如何将对象列表拆分为按元素(日期时间和字符串)分组的子列表 C#
How to Split a object list into sublists grouping by elements(dateTime and String) C#
我正在尝试根据日期时间升序基于包含 9 条记录的主列表制作子列表,然后是 pcName(string)。
我的排序子列表需要如下所示
对象列表 1 :
2615,2019-11-22 16:03:22.150,Test1
2615,2019-11-22 16:03:22.200,Test1
2615,2019-11-22 16:03:22.250,Test1
2615,2019-11-22 16:03:22.300,Test1
对象列表 2 :
2615,2019-11-22 16:03:22.350,Test2
2615,2019-11-22 16:03:22.400,Test2
对象列表 3 :
2615,2019-11-22 16:03:22.450,Test1
2615,2019-11-22 16:03:22.500,Test1
对象列表 4 :
2615,2019-11-22 16:03:22.550,Test3
这个对象列表需要按照ObjectList[0],ObjectList[1],ObjectList[2],ObjectList[3]的顺序取
我在下面提到了我的示例代码
但这只为我提供了 3 个基于 Test1、Test2 和 Test3 的子列表集(Item1)过滤器和 9 个子列表,但我想要上述 4 个子列表。我想在哪里更改代码?? 请帮帮我
private void button_Click(object sender, EventArgs e)
{
List<Identity> listOfIdentity = new List<Identity>()
{
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"),PcName="Test3"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
};
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
var items1 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => x.PcName).Select(grp => grp.ToList()).ToList(); //sub list create based with **Test1, Test2 & Test3** (3 sub lists)
var items2 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => new { x.QCTime, x.PcName }).Select(grp => grp.ToList()).ToList(); //sub list create based with each time and pc name (9 sublists)
}
class Identity
{
public int id { get; set; }
public DateTime QCTime { get; set; }
public string PcName { get; set; }
}
由于您尝试按 DateTime 列进行分组,并且该列仅以毫秒为单位变化,因此分组没有按照您的预期进行。我修改了你的代码如下:
class Identity
{
public int id { get; set; }
public DateTime QCTime { get; set; }
public string PcName { get; set; }
public string QCTimeForGroup
{
get
{
if (QCTime.Millisecond <= 300)
{
return "SL1";
}
else if (QCTime.Millisecond > 300 && QCTime.Millisecond <= 400)
{
return "SL2";
}
else if (QCTime.Millisecond > 400 && QCTime.Millisecond <= 500)
{
return "SL3";
}
return "SL4";
}
}
}
private void button_Click(object sender, EventArgs e)
{
List<Identity> listOfIdentity = new List<Identity>()
{
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"),PcName="Test3"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
};
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
var items1 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => x.PcName).Select(grp => grp.ToList()).ToList(); //sub list create based with **Test1, Test2 & Test3** (3 sub lists)
var items2 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => new { x.QCTime, x.PcName }).Select(grp => grp.ToList()).ToList(); //sub list create based with each time and pc name (9 sublists)
var items3 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName)
.GroupBy(x => new { x.QCTimeForGroup, x.PcName }).Select(grp
=> grp.ToList()).ToList();
}
这是我使用 Linq.Aggregate
的解决方案:
private void button_Click(object sender, EventArgs e)
{
List<Identity> listOfIdentity = new List<Identity>()
{
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"), PcName="Test3"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
};
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
var result = sortedIdentity.Skip(1).Aggregate(new List<List<Identity>> { new List<Identity> { sortedIdentity[0] } }, (lists, curr) =>
{
if (curr.PcName == lists.Last()[0].PcName)
lists.Last().Add(curr);
else
lists.Add(new List<Identity> { curr });
return lists;
});
}
它遍历每个元素并检查它的 PcName 是否与之前的相同。如果是,则它在同一个列表中,否则使用此元素创建新列表。
编辑:Matt.G
建议的更优雅的解决方案
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList();
var result = sortedIdentity.Aggregate(new List<List<Identity>>(), (lists, curr) =>
{
if (curr.PcName == lists.LastOrDefault()?.FirstOrDefault()?.PcName)
lists.Last().Add(curr);
else
lists.Add(new List<Identity> { curr });
return lists;
});
没有专门用于一次性对连续元素进行分组的内置 LINQ 方法。创建一个并不难。一个实现可以在 中找到,签名如下:
public static IEnumerable<IEnumerable<TSource>> SplitByPredicate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, bool> splitPredicate);
您可以像这样使用它来解决您的问题:
var sublists = listOfIdentity
.OrderBy(x => x.QCTime)
.ThenBy(x => x.PcName)
.SplitByPredicate((x, y) => x.PcName != y.PcName);
可以找到不同的实现 ,其签名略有不同:
public static IEnumerable<List<TSource>> GroupConsecutiveByKey<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
...可以这样使用:
var sublists = listOfIdentity
.OrderBy(x => x.QCTime)
.ThenBy(x => x.PcName)
.GroupConsecutiveByKey(x => x.PcName);
我正在尝试根据日期时间升序基于包含 9 条记录的主列表制作子列表,然后是 pcName(string)。
我的排序子列表需要如下所示
对象列表 1 :
2615,2019-11-22 16:03:22.150,Test1
2615,2019-11-22 16:03:22.200,Test1
2615,2019-11-22 16:03:22.250,Test1
2615,2019-11-22 16:03:22.300,Test1
对象列表 2 :
2615,2019-11-22 16:03:22.350,Test2
2615,2019-11-22 16:03:22.400,Test2
对象列表 3 :
2615,2019-11-22 16:03:22.450,Test1
2615,2019-11-22 16:03:22.500,Test1
对象列表 4 :
2615,2019-11-22 16:03:22.550,Test3
这个对象列表需要按照ObjectList[0],ObjectList[1],ObjectList[2],ObjectList[3]的顺序取
我在下面提到了我的示例代码
但这只为我提供了 3 个基于 Test1、Test2 和 Test3 的子列表集(Item1)过滤器和 9 个子列表,但我想要上述 4 个子列表。我想在哪里更改代码?? 请帮帮我
private void button_Click(object sender, EventArgs e)
{
List<Identity> listOfIdentity = new List<Identity>()
{
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"),PcName="Test3"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
};
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
var items1 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => x.PcName).Select(grp => grp.ToList()).ToList(); //sub list create based with **Test1, Test2 & Test3** (3 sub lists)
var items2 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => new { x.QCTime, x.PcName }).Select(grp => grp.ToList()).ToList(); //sub list create based with each time and pc name (9 sublists)
}
class Identity
{
public int id { get; set; }
public DateTime QCTime { get; set; }
public string PcName { get; set; }
}
由于您尝试按 DateTime 列进行分组,并且该列仅以毫秒为单位变化,因此分组没有按照您的预期进行。我修改了你的代码如下:
class Identity
{
public int id { get; set; }
public DateTime QCTime { get; set; }
public string PcName { get; set; }
public string QCTimeForGroup
{
get
{
if (QCTime.Millisecond <= 300)
{
return "SL1";
}
else if (QCTime.Millisecond > 300 && QCTime.Millisecond <= 400)
{
return "SL2";
}
else if (QCTime.Millisecond > 400 && QCTime.Millisecond <= 500)
{
return "SL3";
}
return "SL4";
}
}
}
private void button_Click(object sender, EventArgs e)
{
List<Identity> listOfIdentity = new List<Identity>()
{
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"),PcName="Test3"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
};
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
var items1 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => x.PcName).Select(grp => grp.ToList()).ToList(); //sub list create based with **Test1, Test2 & Test3** (3 sub lists)
var items2 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => new { x.QCTime, x.PcName }).Select(grp => grp.ToList()).ToList(); //sub list create based with each time and pc name (9 sublists)
var items3 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName)
.GroupBy(x => new { x.QCTimeForGroup, x.PcName }).Select(grp
=> grp.ToList()).ToList();
}
这是我使用 Linq.Aggregate
的解决方案:
private void button_Click(object sender, EventArgs e)
{
List<Identity> listOfIdentity = new List<Identity>()
{
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"), PcName="Test3"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
};
List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
var result = sortedIdentity.Skip(1).Aggregate(new List<List<Identity>> { new List<Identity> { sortedIdentity[0] } }, (lists, curr) =>
{
if (curr.PcName == lists.Last()[0].PcName)
lists.Last().Add(curr);
else
lists.Add(new List<Identity> { curr });
return lists;
});
}
它遍历每个元素并检查它的 PcName 是否与之前的相同。如果是,则它在同一个列表中,否则使用此元素创建新列表。
编辑:Matt.G
建议的更优雅的解决方案 List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList();
var result = sortedIdentity.Aggregate(new List<List<Identity>>(), (lists, curr) =>
{
if (curr.PcName == lists.LastOrDefault()?.FirstOrDefault()?.PcName)
lists.Last().Add(curr);
else
lists.Add(new List<Identity> { curr });
return lists;
});
没有专门用于一次性对连续元素进行分组的内置 LINQ 方法。创建一个并不难。一个实现可以在
public static IEnumerable<IEnumerable<TSource>> SplitByPredicate<TSource>(
this IEnumerable<TSource> source,
Func<TSource, TSource, bool> splitPredicate);
您可以像这样使用它来解决您的问题:
var sublists = listOfIdentity
.OrderBy(x => x.QCTime)
.ThenBy(x => x.PcName)
.SplitByPredicate((x, y) => x.PcName != y.PcName);
可以找到不同的实现
public static IEnumerable<List<TSource>> GroupConsecutiveByKey<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
...可以这样使用:
var sublists = listOfIdentity
.OrderBy(x => x.QCTime)
.ThenBy(x => x.PcName)
.GroupConsecutiveByKey(x => x.PcName);