【问题标题】:efficiently creating List<ClassB> from List<ClassA>?从 List<ClassA> 有效地创建 List<ClassB>?
【发布时间】:2017-07-13 20:12:09
【问题描述】:

我有来自 ClassA 的对象,并想用它们来创建 ClassB 的对象。如果我一次只处理一个对象,我知道该怎么做:

ClassA object1 = new ClassA();
ClassB object2 = new ClassB(object1);

class ClassA
{
    public DateTime Timestamp;
    public double X;
    public double Y;
    public double Z;

    public ClassA()
    {
       // other stuff
    }
}

class ClassB
{
    public DateTime Timestamp;
    public double X;

    public ClassB(ClassA A)
    {
        Timestamp = A.Timestamp;
        X = A.X;
    }
}

但是,我正在寻找使用对象列表的最佳方法。我要取 ClassA 类型的列表,并创建 ClassB 类型的列表:

List<ClassA> list_of_classA = new List<ClassA>();
List<ClassB> list_of_classB = ????

【问题讨论】:

  • 假设构造函数相同,你可以list_of_classA.Select(classA =&gt; new ClassB(classA)).ToList()吗?

标签: c# list constructor


【解决方案1】:

除了 Markus 演示的查询样式语法之外,您还可以使用 lambda 样式语法将 ClassA 列表投影到 ClassB

var listOfClassB = list_of_classA.Select(x => new ClassB(x)).ToList()

【讨论】:

  • 效果很好。现在阅读 lambda 风格的语法。谢谢
【解决方案2】:

您可以使用 Linq 将列表投影到 ClassB 类型的新列表:

List<ClassB> list_of_classB = (from x 
                               in list_of_classA
                               select new ClassB(x)).ToList();

首先,您可以在 Linq here 上找到很多好的示例。

【讨论】:

    【解决方案3】:

    只是抛出第三种方式来做到这一点:

    List<ClassA> list_of_classA = new List<ClassA>();
    List<ClassB> list_of_classB = new List<ClassB>();
    
    foreach (ClassA item in list_of_classA)
            {
                list_of_classB.Add(new ClassB(item));
            }
    

    这将在不使用 Linq 或 Lambda 表达式的情况下完成同样的事情。如果可能,您很可能希望使用提供的其他 2 个答案之一。但是,如果您不熟悉 Linq 或 Lambda 表达式,那么这可能会有所帮助。

    【讨论】:

    • 谢谢。就我的目的而言,这工作得很好,并且与根据 System.Diagnostics.Stopwatch 的其他方法一样快
    【解决方案4】:

    您很可能希望按照其他人的建议使用 Select

    也就是说,如果您只想做列表的转换并且性能非常重要,那么 List 有一个名为 ConvertAll 的方法供您使用。

    List<ClassA> list_of_classA = new List<ClassA>();
    List<ClassB> list_of_classB = list_of_classA.ConvertAll((ClassA a) => new ClassB(a));
    

    您可以阅读更多关于使用 Select 和 ConvertAll 的区别 here 表示性能,here 表示它们之间的差异。

    由于 ConvertAll 是不太通用的选项(仅适用于列表),它应该比更通用的 Select 选项更快。我试图通过做一些测试来反驳这个想法。

    我在 A-list 中创建了一个包含 5 和 1000 万个对象的列表,并测试了 ConvertAll 和 Select 选项,得到了以下结果:

    y 轴的单位是毫秒。

    所以数据似乎表明 ConvertAll 实际上要快一些。但是,我的代码可能存在一些导致这些差异的问题,因此请谨慎对待。

    这是我使用的代码。编译发布到 x64。 (还修改了 ListA 使其实际上具有适当的构造函数)

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    
    namespace lekstuga
    {
        class Program
        {
            static void Main(string[] args)
            {
                int loops = 10000000;
    
                for (var n = 0; n < 4; n++)
                {
    
                    Stopwatch stopwatch;
    
                    List<ClassA> listOfClassA2 = new List<ClassA>();
                    List<ClassB> listOfClassB2 = new List<ClassB>();
    
                    for (int i = 0; i < loops; i++)
                    {
                        listOfClassA2.Add(new ClassA(DateTime.Now, 1, 2, 3));
                    }
    
                    stopwatch = Stopwatch.StartNew(); //creates and start the instance of Stopwatch
                    listOfClassB2 = listOfClassA2.ConvertAll((ClassA a) => new ClassB(a));
                    stopwatch.Stop();
    
                    Console.WriteLine("ConvertAll " + stopwatch.ElapsedMilliseconds + "ms");
    
    
                    List<ClassA> listOfClassA = new List<ClassA>();
                    List<ClassB> listOfClassB = new List<ClassB>();
    
                    for (int i = 0; i < loops; i++)
                    {
                        listOfClassA.Add(new ClassA(DateTime.Now, 1, 2, 3));
                    }
    
                    stopwatch = Stopwatch.StartNew(); //creates and start the instance of Stopwatch
                    listOfClassB = listOfClassA.Select(x => new ClassB(x)).ToList();
                    stopwatch.Stop();
    
                    Console.WriteLine("Select " + stopwatch.ElapsedMilliseconds + "ms");
                }
                Console.ReadLine();
            }
    
            class ClassA
            {
                public DateTime Timestamp;
                public double X;
                public double Y;
                public double Z;
    
                public ClassA(DateTime t, double x, double y, double z)
                {
                    Timestamp = t;
                    X = x;
                    Y = y;
                    Z = z;
                }
            }
    
            class ClassB
            {
                public DateTime Timestamp;
                public double X;
    
                public ClassB(ClassA A)
                {
                    Timestamp = A.Timestamp;
                    X = A.X;
                }
            }
        }
    }
    

    最后,关于 Select 的说明,虽然它是惰性的并且在实际需要使用 .ToList() 之前不会执行,但它会强制 LINQ 立即计算数据,因此 Select 和 ConvertAll 在这方面具有可比性。

    【讨论】:

      猜你喜欢
      • 2021-05-22
      • 2021-11-10
      • 1970-01-01
      • 2022-10-13
      • 2020-03-10
      • 1970-01-01
      • 1970-01-01
      • 2011-10-11
      • 2019-09-30
      相关资源
      最近更新 更多