用其他属性从第二个列表填充列表中数据的更快替代方案
本文关键字:列表 方案 数据 属性 其他 第二个 填充 | 更新日期: 2023-09-27 18:26:22
我在SO上搜索了一个解决方案,但找不到,所以我提出了这个新问题。
我有两个不同类别的清单。
头等舱:
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>();
现在我遇到了困难:两个类中的两个属性具有相同的值,但名称不同:即C1Property1 = C2Property1
和C1Property2 = C2Property2
。列表Class1List
的属性C1Property1
为空,我需要使用Class2List
中的属性来填充它。我通过使用以下代码来做到这一点:
foreach(var element1 in Class1List)
{
foreach(var element2 in Class2List)
{
if(element2.C2Property2 == element1.C1Property2)
{
element1.C1Property1 = element2.C2Property1;
}
}
}
这个解决方案按照我的意图工作,但非常难看,我有两个foreach循环,速度可能很慢(列表可能包含超过10000个元素)。在示例类中,我只写了3个属性来展示它的工作原理,但最初它每个都有大约20个属性,其中只有2个是相同的。我能更快、更高效地做到这一点吗?也许是林克?对不起,我无法显示更多代码。我希望你能理解我的要求。我只需要从Class2List
中获取一个属性,并仅当列表中的一个参数相同时将其放置在Class1List
上。
在我的第二次尝试中,我使用了类似的东西:
foreach (var element1 in Class1List)
{
foreach (var element2 in Class2List.Where(element2 => element2.C2Property2 == element1.C1Property2 ))
{
element2.C2Property2 = element1.C1Property2;
break;
}
}
这应该更快,但看起来仍然很难看
所以这里有三个选项:
使用LINQ
Class1List.ForEach(element1 =>
{
Class2 element2 = Class2List.FirstOrDefault(e2 => e2.C2Property2 == element1.C1Property2);
if (element2 != null) element1.C1Property1 = element2.C2Property1;
});
对于每个列表中的20000个元素,我的机器花费了4.58秒。虽然代码看起来(对我来说)稍微好一点,但这实际上与您的代码相同。
使用字典
使用字典通过散列访问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;
});
对于每个列表中的20000个元素,我的机器花费了0.00878秒。
平行
如果你的数据真的非常大,你可以考虑使用Parallel.For Each
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;
});
但由于每个列表中只有20000个元素,我的机器比非并行版本花费了更长的时间(0.0197秒)。
这是一件非常有趣的事情,但我认为这样的事情可能会奏效:
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();
}
}
}
输出:
BEFORE
ListA: (5, ), (16, ), (9, ), (38, )
ListB: (5, 1), (9, 2), (16, 3)
AFTER
ListA: (5, 1), (16, 3), (9, 2), (38, )
ListB: (5, 1), (9, 2), (16, 3)