我有一个通用的List(Foo),它包含了Type Foo的n个对象。 Foo的一个属性是PropertyA。 PropertyA可以是ValueA,ValueB或ValueC之一。有没有一种简单的方法可以将它分成三个单独的列表,一个用于ValueA,一个用于ValueB,一个用于ValueC?
我可以编写一些循环原始列表的代码,并根据属性值将每个项目添加到一个新列表中,但这似乎不是很容易维护(如果我突然得到一个ValueD,那该怎么办?)
**编辑。我应该提到我正在使用该框架的2.0版本。
答案 0 :(得分:5)
在C#中我会写:
List<List<foo>> result = fooList
.GroupBy(foo => foo.PropertyA)
.Select(g => g.ToList())
.ToList();
答案 1 :(得分:5)
如果你想要valueA,valueB和valueC的3个列表(即使其中一个是空的):
Dim listA = (From x in myList Where x.PropertyA = ValueA).ToList()
Dim listB = (From x in myList Where x.PropertyA = ValueB).ToList()
...
否则,请按照其他人的建议使用GroupBy运算符。
Dim dic as New Dictionary(Of TypeOfYourValues, List(Of Foo))
For Each e As Foo In myList
If Not dic.ContainsKey(e.PropertyA) Then
dic(e.PropertyA) = New List(Of Foo)
End if
dic(e.PropertyA).Add(e)
Next
然后循环遍历字典的值。
答案 2 :(得分:5)
在C#中使用.Net 2.0,我写过(太多次):
//if PropertyA is not int, change int to whatever that type is
Dictionary<int, List<foo>> myCollections =
new Dictionary<int, List<foo>>();
//
foreach(Foo myFoo in fooList)
{
//if I haven't seen this key before, make a new entry
if (!myCollections.ContainsKey(myFoo.PropertyA))
{
myCollections.Add(myFoo.PropertyA, new List<foo>());
}
//now add the value to the entry.
myCollections[myFoo.PropertyA].Add(myFoo);
}
//
// now recollect these lists into the result.
List<List<Foo>> result = new List<List<Foo>>();
foreach(List<Foo> someFoos in myCollections.Values)
{
result.Add(someFoos);
}
如今,我只想写:
List<List<foo>> result = fooList
.GroupBy(foo => foo.PropertyA)
.Select(g => g.ToList())
.ToList();
或者
ILookup<TypeOfPropertyA, foo>> result = fooList.ToLookup(foo => foo.PropertyA);
答案 3 :(得分:3)
您可以使用Enumerable.GroupBy:
var groupings = list.GroupBy(x => x.PropertyA);
foreach(var grouping in groupings)
{
// grouping.Key is the grouped value
foreach(var entry in grouping)
{
// process
}
}
答案 4 :(得分:3)
请参阅下面的C#获取VB.Net版本 - 请注意,由于VB.NET中没有匿名方法,因此还有一个额外的类(FooFinder),所以我需要能够存储匹配状态的东西。
这是一种更“功能”的方式来完成同样的事情,但仍然使用C#2.0语法。请注意,与其他解决方案(循环/字典)的重要区别在于使用List上的FindAll方法,它将迭代您的集合并返回委托返回true的所有项目。 C#:
using System;
using System.Collections.Generic;
namespace SplitList
{
class Program
{
class Foo
{
public Foo(string propertyA, int number)
{
_propertyA = propertyA;
_number = number;
}
private int _number;
private string _propertyA;
public string PropertyA
{
get { return _propertyA; }
}
public int Number
{
get { return _number; }
}
}
static void Main(string[] args)
{
List<Foo> foos = new List<Foo>();
foos.Add(new Foo("ValueA", 1));
foos.Add(new Foo("ValueA", 2));
foos.Add(new Foo("ValueA", 3));
foos.Add(new Foo("ValueA", 4));
foos.Add(new Foo("ValueB", 5));
foos.Add(new Foo("ValueB", 6));
foos.Add(new Foo("ValueC", 7));
foos.Add(new Foo("ValueC", 8));
foos.Add(new Foo("ValueC", 9));
List<Foo> aFoos = foos.FindAll(delegate(Foo f) { return f.PropertyA == "ValueA"; });
List<Foo> bFoos = foos.FindAll(delegate(Foo f) { return f.PropertyA == "ValueB"; });
List<Foo> cFoos = foos.FindAll(delegate(Foo f) { return f.PropertyA == "ValueC"; });
WriteFoos("ValueA", aFoos);
WriteFoos("ValueB", bFoos);
WriteFoos("ValueC", cFoos);
Console.ReadLine();
}
private static void WriteFoos(string propertyAValue, List<Foo> list)
{
Console.WriteLine("Group {0}:", propertyAValue);
list.ForEach(delegate(Foo f)
{
Console.WriteLine("Number:{0}, PropertyA:{1}", f.Number, f.PropertyA);
});
}
}
}
VB.NET:
Module Module1
Class FooFinder
Public Sub New(ByVal propertyAValue As String)
Me.PropertyAValue = propertyAValue
End Sub
Public ReadOnly PropertyAValue As String
Function Matches(ByVal f As Foo) As Boolean
Return (f.PropertyAValue = Me.PropertyAValue)
End Function
End Class
Class Foo
Public Sub New(ByVal propertyAValue As String, ByVal number As Integer)
_propertyAValue = propertyAValue
_number = number
End Sub
Private _propertyAValue As String
Private _number As Integer
Public Property PropertyAValue() As String
Get
Return _propertyAValue
End Get
Set(ByVal value As String)
_propertyAValue = value
End Set
End Property
Public Property Number() As Integer
Get
Return _number
End Get
Set(ByVal value As Integer)
_number = value
End Set
End Property
End Class
Sub Main()
Dim foos As New List(Of Foo)
foos.Add(New Foo("ValueA", 1))
foos.Add(New Foo("ValueA", 2))
foos.Add(New Foo("ValueA", 3))
foos.Add(New Foo("ValueB", 4))
foos.Add(New Foo("ValueB", 5))
foos.Add(New Foo("ValueC", 6))
foos.Add(New Foo("ValueC", 7))
foos.Add(New Foo("ValueC", 8))
foos.Add(New Foo("ValueC", 9))
Dim aFoos As List(Of Foo) = foos.FindAll(AddressOf New FooFinder("ValueA").Matches)
Dim bFoos As List(Of Foo) = foos.FindAll(AddressOf New FooFinder("ValueB").Matches)
Dim cFoos As List(Of Foo) = foos.FindAll(AddressOf New FooFinder("ValueC").Matches)
WriteFoos("ValueA", aFoos)
WriteFoos("ValueB", bFoos)
WriteFoos("ValueC", cFoos)
Console.ReadLine()
End Sub
Private Sub WriteFoos(ByVal propertyAValue As String, ByVal list As List(Of Foo))
Console.WriteLine("PropertyAValue:{0}", propertyAValue)
For Each f As Foo In list
Console.WriteLine("Number:{0}, PropertyAValue:{1}", f.Number, f.PropertyAValue)
Next
End Sub
End Module
答案 5 :(得分:1)
var query = from foo in list
group foo by foo.PropertyA;
List<Foo> valueAGroup = query.First(g => g.Key == ValueA).ToList();
List<Foo> valueBGroup = query.First(g => g.Key == ValueB).ToList();
List<Foo> valueCGroup = query.First(g => g.Key == ValueC).ToList();
如果ToList()
足够好,您可以省略IEnumerable<Foo>
次来电。
如果ValueX可能没有PropertyA等于ValueX的项,那么First
将抛出异常。在这种情况下,最好这样做:
List<Foo> valueXGroup = (query.FirstOrDefault(g => g.Key == ValueX) ??
Enumerable.Empty<Foo>()).ToList();
这将为您提供一个空列表,而不是抛出异常。