C# 使用其他属性更快地从第二个列表填充列表中的数据

C# 使用其他属性更快地从第二个列表填充列表中的数据,c#,.net,linq,list,foreach,C#,.net,Linq,List,Foreach,我一直在寻找解决方案,但我找不到,所以我提出了这个新问题 我有两个不同班级的名单 头等舱: public class Class1 { public int C1Property1 {get;set;} public int C1Property2 {get;set;} public int C1Property3 {get;set;} } 二等舱: public class Class2 { public int C2Property1 {get;set;}

我一直在寻找解决方案,但我找不到,所以我提出了这个新问题

我有两个不同班级的名单

头等舱:

public class Class1
{
    public int C1Property1 {get;set;}
    public int C1Property2 {get;set;}
    public int C1Property3 {get;set;}
}
二等舱:

public class Class2
{
    public int C2Property1 {get;set;}
    public int C2Property2 {get;set;}
    public int C2Property3 {get;set;}
}
我有两个课程列表:

List<Class1> Class1List = new List<Class1>();
List<Class2> Class2List = new List<Class2>();
这个解决方案按照我的意图工作,但非常难看,我有2个foreach循环,速度很慢(列表可以包含10000多个元素)。在示例类中,我只编写了3个属性来说明它是如何工作的,但最初每个类都有约20个属性,其中只有2个是相同的。我能更快更有效地完成这项工作吗?也许是林克?对不起,我无法显示更多的代码。我希望你能理解我的要求。 我只需要从
Class2List
中获取一个属性,并且仅当列表中的一个参数相同时,才将其放置在
classlist

在我的第二次尝试中,我使用了如下内容:

foreach (var element1 in Class1List)
{
    foreach (var element2 in Class2List.Where(element2 => element2.C2Property2 == element1.C1Property2 ))
    {
        element2.C2Property2 = element1.C1Property2;
        break;
    }
}

这应该更快,但看起来仍然很难看

这是一件非常有趣的事情,但我认为类似的方法可能会奏效:

Class1List.ForEach(c1 =>
    c1.C1Property1 = Class2List.Where(c2 => c2.C2Property2 == c1.C1Property2)
                               .Select(r => r.C2Property1)
                               .FirstOrDefault());
下面是一个测试类:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SO_Test
{
    public class ObjectA
    {
        public int Property1 { get; set; }
        public int? Property2 { get; set; }

        public override string ToString()
        {
            return String.Format("({0}, {1})", Property1, Property2);
        }
    }

    public class ObjectB
    {
        public int Property1 { get; set; }
        public int? Property2 { get; set; }

        public override string ToString()
        {
            return String.Format("({0}, {1})", Property1, Property2);
        }
    }

    class Program
    {
        static void Main()
        {
            var listA = new List<ObjectA>
            { 
                new ObjectA { Property1 = 5,  Property2 = null }, 
                new ObjectA { Property1 = 16, Property2 = null }, 
                new ObjectA { Property1 = 9,  Property2 = null }, 
                new ObjectA { Property1 = 38, Property2 = null } 
            };
            var listB = new List<ObjectB>
            { 
                new ObjectB { Property1 = 5, Property2 = 1 }, 
                new ObjectB { Property1 = 9, Property2 = 2 }, 
                new ObjectB { Property1 = 16, Property2 = 3 } 
            };

            Console.WriteLine("BEFORE");
            Console.WriteLine("ListA: {0}", String.Join(", ", listA));
            Console.WriteLine("ListB: {0}", String.Join(", ", listB));

            listA.ForEach(a =>
                a.Property2 = listB.Where(b => b.Property1 == a.Property1)
                                   .Select(r => r.Property2)
                                   .FirstOrDefault());

            Console.WriteLine("AFTER");
            Console.WriteLine("ListA: {0}", String.Join(", ", listA));
            Console.WriteLine("ListB: {0}", String.Join(", ", listB));
            Console.ReadLine();
        }
    }
}

这是一件非常有趣的事情,但我认为类似的事情可能会奏效:

Class1List.ForEach(c1 =>
    c1.C1Property1 = Class2List.Where(c2 => c2.C2Property2 == c1.C1Property2)
                               .Select(r => r.C2Property1)
                               .FirstOrDefault());
下面是一个测试类:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SO_Test
{
    public class ObjectA
    {
        public int Property1 { get; set; }
        public int? Property2 { get; set; }

        public override string ToString()
        {
            return String.Format("({0}, {1})", Property1, Property2);
        }
    }

    public class ObjectB
    {
        public int Property1 { get; set; }
        public int? Property2 { get; set; }

        public override string ToString()
        {
            return String.Format("({0}, {1})", Property1, Property2);
        }
    }

    class Program
    {
        static void Main()
        {
            var listA = new List<ObjectA>
            { 
                new ObjectA { Property1 = 5,  Property2 = null }, 
                new ObjectA { Property1 = 16, Property2 = null }, 
                new ObjectA { Property1 = 9,  Property2 = null }, 
                new ObjectA { Property1 = 38, Property2 = null } 
            };
            var listB = new List<ObjectB>
            { 
                new ObjectB { Property1 = 5, Property2 = 1 }, 
                new ObjectB { Property1 = 9, Property2 = 2 }, 
                new ObjectB { Property1 = 16, Property2 = 3 } 
            };

            Console.WriteLine("BEFORE");
            Console.WriteLine("ListA: {0}", String.Join(", ", listA));
            Console.WriteLine("ListB: {0}", String.Join(", ", listB));

            listA.ForEach(a =>
                a.Property2 = listB.Where(b => b.Property1 == a.Property1)
                                   .Select(r => r.Property2)
                                   .FirstOrDefault());

            Console.WriteLine("AFTER");
            Console.WriteLine("ListA: {0}", String.Join(", ", listA));
            Console.WriteLine("ListB: {0}", String.Join(", ", listB));
            Console.ReadLine();
        }
    }
}

因此,我有三个选择:

使用LINQ 我的机器用了4.58秒,每个列表中有20000个元素。虽然代码看起来(在我看来)好一点,但实际上它与您的代码是一样的

使用字典 使用字典通过散列访问
Class2
元素非常有效:

Dictionary<int, Class2> dictionary =                Class2List.GroupBy(e2 => e2.C2Property2, e2 => e2).Select(elements => elements.First()).ToDictionary(e2 => e2.C2Property2, e2 => e2);

Class1List.ForEach(element1 =>
{
    if (dictionary.ContainsKey(element1.C1Property2))
        element1.C1Property1 = dictionary[element1.C1Property2].C2Property1;
});
Dictionary Dictionary=Class2List.GroupBy(e2=>e2.C2Property2,e2=>e2)。选择(elements=>elements.First()).ToDictionary(e2=>e2.C2Property2,e2=>e2);
ClassList.ForEach(元素1=>
{
if(dictionary.ContainsKey(element1.C1Property2))
element1.C1Property1=字典[element1.C1Property2].C2Property1;
});
这使我的机器在每个列表中花费了0.00878个元素

平行的 <>如果你的数据真的很大,你可以考虑使用< /P>
字典=
GroupBy(e2=>e2.C2Property2,e2=>e2)。选择(elements=>elements.First()).ToDictionary(e2=>e2.C2Property2,e2=>e2);
Parallel.ForEach(ClassList,element1=>
{
if(dictionary.ContainsKey(element1.C1Property2))
element1.C1Property1=字典[element1.C1Property2].C2Property1;
});

但由于每个列表中只有20000个元素,因此我的机器比非并行版本花费的时间更长(0.0197s)。

因此,我有三个选项:

使用LINQ 我的机器用了4.58秒,每个列表中有20000个元素。虽然代码看起来(在我看来)好一点,但实际上它与您的代码是一样的

使用字典 使用字典通过散列访问
Class2
元素非常有效:

Dictionary<int, Class2> dictionary =                Class2List.GroupBy(e2 => e2.C2Property2, e2 => e2).Select(elements => elements.First()).ToDictionary(e2 => e2.C2Property2, e2 => e2);

Class1List.ForEach(element1 =>
{
    if (dictionary.ContainsKey(element1.C1Property2))
        element1.C1Property1 = dictionary[element1.C1Property2].C2Property1;
});
Dictionary Dictionary=Class2List.GroupBy(e2=>e2.C2Property2,e2=>e2)。选择(elements=>elements.First()).ToDictionary(e2=>e2.C2Property2,e2=>e2);
ClassList.ForEach(元素1=>
{
if(dictionary.ContainsKey(element1.C1Property2))
element1.C1Property1=字典[element1.C1Property2].C2Property1;
});
这使我的机器在每个列表中花费了0.00878个元素

平行的 <>如果你的数据真的很大,你可以考虑使用< /P>
字典=
GroupBy(e2=>e2.C2Property2,e2=>e2)。选择(elements=>elements.First()).ToDictionary(e2=>e2.C2Property2,e2=>e2);
Parallel.ForEach(ClassList,element1=>
{
if(dictionary.ContainsKey(element1.C1Property2))
element1.C1Property1=字典[element1.C1Property2].C2Property1;
});

但由于每个列表中只有20000个元素,我的机器比非并行版本花费的时间更长(0.0197s)。

我编辑了你的文章,因此更容易阅读。至于你的问题,我不知道如何使它更有效率。即使您确实使用Linq使其成为一个单行程序,如果我没有弄错的话,它仍然会在幕后执行foreach循环。但是这里有很多人的知识比我多,所以也许其他人有一个可行的建议@NSNoob该问题将两个不同类的列表合并为一个,而OP希望将list1中一个对象值的属性设置为list2中的另一个对象值(并比较其他两个属性是否相等)。@KevinCruijssen oh Ok。谢谢你解释kevinYea对英语很抱歉,我知道这很难理解:)你为什么不在设置好酒店后休息一下呢?Class2List中是否有可能(并且想要)有更多的元素具有相同的属性并且应该更改element1的属性?这不是1的最快解决方案。对两个列表进行排序,2。使用带有
index1
index2
的单个
while
,其中只增加索引,从而松开
list1.PropertyA.CompareTo(list2.Property2)
。应该给你更少的迭代次数。特别是如果列表相似的话。我已经编辑了你的帖子,这样更容易阅读。至于你的问题,我不知道如何使它更有效率。即使您确实使用Linq使其成为一个单行程序,如果我没有弄错的话,它仍然会在幕后执行foreach循环。但是这里有很多人的知识比我多,所以也许其他人有一个可行的建议@NSNoob该问题将两个不同类的列表合并为一个,而OP希望将list1中一个对象值的属性设置为list2中的另一个对象值(并比较其他两个属性是否相等)。@KevinCruijssen oh Ok。谢谢你解释kevinYea对英语很抱歉,我知道这很难理解:)你为什么不在设置好酒店后休息一下呢?Class2List中是否可能(并且需要)有更多的元素具有相同的属性并且应该更改element1的属性?这不是最快的解决方案吗
Dictionary<int, Class2> dictionary =
            Class2List.GroupBy(e2 => e2.C2Property2, e2 => e2).Select(elements => elements.First()).ToDictionary(e2 => e2.C2Property2, e2 => e2);

Parallel.ForEach(Class1List, element1 =>
{
    if (dictionary.ContainsKey(element1.C1Property2))
        element1.C1Property1 = dictionary[element1.C1Property2].C2Property1;
});