C#/ LINQ比较两个列表并赋值

时间:2017-02-20 17:26:13

标签: c# linq list c#-4.0 iequalitycomparer

我已经制作了一个基本上比较C#中两个列表的代码。第一个列表包含如下属性:

  • 的ItemID
  • TOTALVIEWS

第一个列表缺少TotalViews的值,所以我从第二个列表中分配它们,这些列表包含这些道具:

  • 的ItemID
  • HitCount //这是需要分配的TotalViews的属性

代码如下:

foreach (var item in parsedMerchantData)
{
    var itemInB = HitCountItemIDS.FirstOrDefault(x => x.ItemID == item.ItemID);
    if (itemInB != null)
    {
        if (itemInB.HitCount != -1)
        {
            item.TotalViews = itemInB.HitCount;
        }
        else
        {
            item.TotalViews = 0;
        }
    }
}

有没有更有效的方法来使用LINQ或实现自定义比较器来编写它,它可以更快地在包含有效10万个项目的较大列表上工作?

4 个答案:

答案 0 :(得分:4)

这就像jdweng的答案,但稍微简单一点,它不会因缺少物品ID而抛出异常:

var hitCountsById = HitCountItemIDS.ToDictionary(x => x.ItemID, x => x.HitCount);
foreach (var item in parsedMerchantData)
{
    int hitCount;
    // We don't care about the return value of TryGetValue here...
    hitCountsById.TryGetValue(item.ItemID, out hitCount);
    item.HitCount = hitCount == -1 ? 0 : hitCount;
}

这应该是O(N + M),其中N是HitCountItemIDs的大小而MparsedMerchantData的大小...所以当数据变大时,它应该是应该比合并排序方法更慢,并且绝对是更简单的代码。 (它不需要比较项目ID进行排序,或者只是相等。)

答案 1 :(得分:2)

代码如下所示。不确定HitCountItemID的类型是什么。如果它是匿名的,那么只需制作'var dict':

Dictionary<string, ABC_TYPE> dict = HitCountItemID.GropupBy(x => x.ItemID, y => y).ToDictionary(x => x.Key, y => y.FirstOrDefault())
foreach (var item in parsedMerchantData)
{
    var itemInB = dict[item.ItemID];
    if (itemInB != null)
    {
        if (itemInB.HitCount != -1)
        {
            item.TotalViews = itemInB.HitCount;
        }
        else
        {
            item.TotalViews = 0;
        }
    }
}

答案 2 :(得分:2)

我假设您在程序运行/收集数据期间持有2个列表,因此您可以在插入期间对它们进行排序。或者,如果它们在数据库中并且ID上有索引,那么它也可以工作。

如果是这样,你应该能够只运行一个数组,这将优化程序真正高(现在你有大约n ^ 2复杂性取决于值),你改变后你会有n。

int i = 0, j = 0;

while( i < parsedMerchantData.Count && j < HitCountItemIDS.Count)
{
    var item = parsedMerchantData[i];
    var itemInB = HitCountItemIDS[j];

    if (itemInB.ItemID == item.ItemID)
    {
        item.TotalViews = (itemInB.HitCount > 0) ? itemInB.HitCount : 0;
        i++;
        j++;
    }
    else if(itemInB.ItemID < item.ItemID)
        i++;
    else  //itemInB.ItemID > item.ItemID
        j++;
}

代码应该与上面的代码类似,你应该添加更多关于它何时结束的控制权。其余值应该发生什么(这将在ij结束时停止。

答案 3 :(得分:2)

这是伪代码:

var arr1 = parsedMerchantData.OrderBy(x => x.ItemID).ToArray();
var arr2 = HitCountItemID.OrderBy(x => x.ItemID).ToArray();

var i, j = 0;
while(i + j < arr1.Length() + arr2.Length()) // or similar condition
{
    if (arr1[i].ItemID < arr2[j].ItemID) {
        if (i < arr1.Length() - 1) {
            i++;
        }
        continue;
    }

    if (arr1[i].ItemID > arr2[j].ItemID) {
        if (j < arr2.Length() - 1) {
            j++;
        }
        continue;
    }

    if (arr1[i].ItemID == arr2[j].ItemID) {
        arr1[i].TotalViews = arr2[j].HitCount != -1 ? arr2[j].HitCount : 0;
    }

    // Make sure you do not let i and j grow higher then lengths of arrays
}

这个想法是应用MergeSort算法。 至于复杂性,你花O(n * log(n))排序每个列表然后O(n)通过它们。总数是O(n * log(n)),这是我看到的最快的方式。