.net 如何基于列表成员的属性拆分(T的)泛型列表?

.net 如何基于列表成员的属性拆分(T的)泛型列表?,.net,vb.net,generics,.net-2.0,.net,Vb.net,Generics,.net 2.0,我有一个Foo的通用列表,其中包含n个Foo类型的对象。Foo的属性之一是PropertyA。房地产A可以是ValueA、ValueB或ValueC中的一种。有没有一种简单的方法可以将其分为三个单独的列表,一个用于ValueA,一个用于ValueB,一个用于ValueC 我可以编写一些代码来循环原始列表,并根据属性值将每个项添加到新列表中,但这似乎不是很容易维护,例如,如果我突然得到一个值会怎么样 **编辑。我应该提到我正在使用框架的2.0版。您可以使用: 我会用C写: List<Li

我有一个Foo的通用列表,其中包含n个Foo类型的对象。Foo的属性之一是PropertyA。房地产A可以是ValueA、ValueB或ValueC中的一种。有没有一种简单的方法可以将其分为三个单独的列表,一个用于ValueA,一个用于ValueB,一个用于ValueC

我可以编写一些代码来循环原始列表,并根据属性值将每个项添加到新列表中,但这似乎不是很容易维护,例如,如果我突然得到一个值会怎么样

**编辑。我应该提到我正在使用框架的2.0版。

您可以使用:

我会用C写:

  List<List<foo>> result = fooList
    .GroupBy(foo => foo.PropertyA)
    .Select(g => g.ToList())
    .ToList();

如果您想要valueA、valueB和valueC的三个列表,即使其中一个为空:

Dim listA = (From x in myList Where x.PropertyA = ValueA).ToList()
Dim listB = (From x in myList Where x.PropertyA = ValueB).ToList()
...
否则,请按照其他人的建议使用GroupBy运算符

编辑:由于您使用的是Framework2.0,我想您必须求助于您的循环思想。不过,实现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
然后循环浏览字典中的值

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();

这将为您提供一个空列表,而不是引发异常。

请参见下面的C以了解VB.Net版本-注意,由于VB.Net中没有匿名方法,因此有一个额外的类FooFinder,因此我需要一些东西来存储匹配状态

这里有一个更实用的方法来完成同样的事情,但仍然使用C2.0语法。请注意,与其他循环/字典解决方案的重要区别在于使用列表上的FindAll方法,它将迭代您的集合并返回委托返回true的所有项。 C:


在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();


+1.Telerik converter说VB等价物是暗淡的结果,因为ListOf ListOf foo=傻瓜。GroupByFunctionfoo作为foo.PropertyA。[选择]Functiong作为g.ToList.ToListI我非常喜欢这样的外观,通过Telerik转换到VB会在“函数”一词上出现编译错误,你知道这将如何翻译吗?Dim aFoos As ListOf Foo=foos.FindAllFunctionf As Foo Do Return f.PropertyA=ValueA End function我已经用VB.NET版本更新了我的响应-略有不同,因为VB.NET 2.0中缺少匿名方法/委托,但基本思想相同。如果没有带ValueA的项目,这不会引发问题吗?
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);
                             });

        }
    }
}
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
 //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);