迭代两个列表,并在匹配元素上更新数值。

huangapple go评论63阅读模式
英文:

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:

  1. find all members exists with same id
  2. set InternalRef value from list2 member to the matching list1 member where InternalRef 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&lt;Car&gt;();
list1.Add(new Car { Id = 1, Name = &quot;Audi&quot;, InternalRef = &quot;abc&quot; });
list1.Add(new Car { Id = 2, Name = &quot;Toyota&quot;, InternalRef = &quot;dfg&quot; });
list1.Add(new Car { Id = 3, Name = &quot;Seat&quot; });

var list2 = new List&lt;Car&gt;();
list2.Add(new Car { Id = 1, Name = &quot;Audi&quot;, InternalRef = &quot;abc&quot; });
list2.Add(new Car { Id = 2, Name = &quot;Toyota&quot;, InternalRef = &quot;dfg&quot; });
list2.Add(new Car { Id = 3, Name = &quot;Seat&quot;, InternalRef = &quot;xvc&quot; });


var comparer = new MyComparer();    
for (int i = 0; i &lt; list1.Count(); i++)
{
    var car = list1[i];
    int index = list2.BinarySearch(car, comparer);  
    
    if (index &gt; 0 &amp;&amp; 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&lt;Car&gt;
{
    public override int Compare(Car x, Car y) =&gt; 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&lt;Car&gt;();
list1.Add(new Car { Id = 1, Name = &quot;Audi&quot;, InternalRef = &quot;abc&quot; });
list1.Add(new Car { Id = 2, Name = &quot;Toyota&quot;, InternalRef = &quot;dfg&quot; });
list1.Add(new Car { Id = 3, Name = &quot;Seat&quot; });

var list2 = new List&lt;Car&gt;();
list2.Add(new Car { Id = 1, Name = &quot;Audi&quot;, InternalRef = &quot;abc&quot; });
list2.Add(new Car { Id = 2, Name = &quot;Toyota&quot;, InternalRef = &quot;dfg&quot; });
list2.Add(new Car { Id = 3, Name = &quot;Seat&quot;, InternalRef = &quot;xvc&quot; });

// Actual code
foreach (var car in list1) {
    car.InternalRef ??= list2.FirstOrDefault(x =&gt; 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.

huangapple
  • 本文由 发表于 2023年5月30日 11:13:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76361396.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定