英文:
Iterate two lists and update value on matching element
问题
var combined = (from c in list1 where list2.Any(x => c.Id == x.Id) select c).ToList();
这段代码会给我一个具有相同Id的所有成员的组合列表,但我仍然需要一种方法来设置InternalRef的值。
英文:
public class Car
{
public string Name {get; set;}
public string? InternalRef {get; set;}
}
var list1 = new List<Car>();
list1.Add(new Car{ Id = 1, Name = "Audi", InternalRef = "abc"});
list1.Add(new Car{ Id = 2, Name = "Toyota", InternalRef = "dfg"});
list1.Add(new Car{ Id = 3, Name = "Seat" });
var list2 = new List<Car>();
list2.Add(new Car{ Id = 1, Name = "Audi", InternalRef = "abc"});
list2.Add(new Car{ Id = 2, Name = "Toyota", InternalRef = "dfg"});
list2.Add(new Car{ Id = 3, Name = "Seat", InternalRef = "xvc" });
I want to iterate both lists and:
- find all members exists with same id
- set
InternalRef
value fromlist2
member to the matchinglist1
member whereInternalRef
is null.
var combined = (from c in list1 where list2.Any(x => c.Id == x.Id) select c).ToList();
> This will give me a combined list for all members with the same Id, but I still need a way to set InternalRef value
答案1
得分: 2
如果我们可以假设列表按照 Id
排序,就像你的示例代码中一样,那么你可以使用二分搜索来在列表之间找到匹配项,并在 InternalRef
为空时进行设置,非常迅速。
var list1 = new List<Car>();
list1.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list1.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list1.Add(new Car { Id = 3, Name = "Seat" });
var list2 = new List<Car>();
list2.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list2.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list2.Add(new Car { Id = 3, Name = "Seat", InternalRef = "xvc" });
var comparer = new MyComparer();
for (int i = 0; i < list1.Count(); i++)
{
var car = list1[i];
int index = list2.BinarySearch(car, comparer);
if (index > 0 && car.InternalRef is null)
{
car.InternalRef = list2[index].InternalRef;
}
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public string? InternalRef { get; set; }
}
public class MyComparer : Comparer<Car>
{
public override int Compare(Car x, Car y) => x.Id.CompareTo(y.Id);
}
英文:
If we can assume the lists are sorted by Id
as in your example code then you could use binary search to find matches between lists and set InternalRef
where null rather quickly.
var list1 = new List<Car>();
list1.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list1.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list1.Add(new Car { Id = 3, Name = "Seat" });
var list2 = new List<Car>();
list2.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list2.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list2.Add(new Car { Id = 3, Name = "Seat", InternalRef = "xvc" });
var comparer = new MyComparer();
for (int i = 0; i < list1.Count(); i++)
{
var car = list1[i];
int index = list2.BinarySearch(car, comparer);
if (index > 0 && car.InternalRef is null)
{
car.InternalRef = list2[index].InternalRef;
}
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public string? InternalRef { get; set; }
}
public class MyComparer : Comparer<Car>
{
public override int Compare(Car x, Car y) => x.Id.CompareTo(y.Id);
}
答案2
得分: 1
与尝试使用LINQ将每个匹配的元素组合,然后设置值不同,为什么不只是迭代list1
,然后,如果汽车缺少值,您可以在第二个列表中查找它:
// 设置
var list1 = new List<Car>();
list1.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list1.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list1.Add(new Car { Id = 3, Name = "Seat" });
var list2 = new List<Car>();
list2.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list2.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list2.Add(new Car { Id = 3, Name = "Seat", InternalRef = "xvc" });
// 实际代码
foreach (var car in list1) {
car.InternalRef ??= list2.FirstOrDefault(x => x.Id == car.Id)?.InternalRef;
}
编辑以添加到帖子评论中有关时间复杂性的讨论:从实际上来看,这将具有与当前算法类似的最坏情况时间复杂性,但实际上会更高效,因为我们只在list1
中那些没有InternalRef
的元素中进行了查找。因此,如果list1
中的大多数元素已经具有InternalRef
,那么我们需要进行的查找数量大大减少。
英文:
Rather than trying to combine each matching element with LINQ and then set the value, why don't you just iterate list1
and then, if the car is missing the value, you can look it up in the second list:
// Setup
var list1 = new List<Car>();
list1.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list1.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list1.Add(new Car { Id = 3, Name = "Seat" });
var list2 = new List<Car>();
list2.Add(new Car { Id = 1, Name = "Audi", InternalRef = "abc" });
list2.Add(new Car { Id = 2, Name = "Toyota", InternalRef = "dfg" });
list2.Add(new Car { Id = 3, Name = "Seat", InternalRef = "xvc" });
// Actual code
foreach (var car in list1) {
car.InternalRef ??= list2.FirstOrDefault(x => x.Id == car.Id)?.InternalRef;
}
Edit to add to the discussion about time complexity in the post comments: this will have a similar worst-case time complexity as your current algorithm, but in practice will be more efficient because we're only doing a lookup in list2
for those elements of list1
that don't have an InternalRef
. So we greatly reduce the number of lookups we need to do if most elements in list1
already have an InternalRef
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论