Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何有效地比较C#中两个大型对象列表的属性?_C# - Fatal编程技术网

如何有效地比较C#中两个大型对象列表的属性?

如何有效地比较C#中两个大型对象列表的属性?,c#,C#,我有一个包含两个对象列表的数据集,它的ID在两个列表中都是一致的,但其他属性可能不同,也可能不同。如何最有效地检索基于一个或多个属性的不同属性 我通常的做法是这样的。我的对象设置如下: public class Person { public int ID { get; set; } public string Name { get; set; } public int Age { get; set;

我有一个包含两个对象列表的数据集,它的ID在两个列表中都是一致的,但其他属性可能不同,也可能不同。如何最有效地检索基于一个或多个属性的不同属性

我通常的做法是这样的。我的对象设置如下:

   public class Person
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }

            public bool IsEqual(Person other)
            {
                if (Name != other.Name)
                {
                    return false;
                }
                if (Age != other.Age)
                {
                    return false;
                }
                return true;
            }
        } 
其中,使用等质量比较器将其与某个等效对象进行比较

然后我找到被改造人的方法是:

  public static List<Person> FindModifiedPeople(List<Person> listA, List<Person> listB)
        {
            var modifiedPeople = new List<Person>();
            foreach (var personA in listA)
            {
                var matchingPerson = listB.FirstOrDefault(e => e.ID == personA.ID);
                if (matchingPerson == null)
                {
                    continue;
                }

                if (!personA.IsEqual(matchingPerson))
                {
                    modifiedPeople.Add(personA);
                }
            }
            return modifiedPeople;
        }
公共静态列表FindModifiedPeople(列表A、列表B)
{
var modifiedPeople=新列表();
foreach(listA中的var personA)
{
var matchingPerson=listB.FirstOrDefault(e=>e.ID==personA.ID);
if(matchingPerson==null)
{
继续;
}
如果(!personA.IsEqual(匹配人))
{
修改人物。添加(人物角色);
}
}
返回修改人;
}
在我的数据集中,我不关心listB中的人,但不关心listA中的人,所以我不需要遍历这两个列表。我只需要在listB中检查listA中的元素(可能存在也可能不存在),并返回一个已修改的人员列表(使用listA中的元素)


这种方法适用于相当小的列表,但现在我有两个约160000人的列表,这种方法需要几分钟。有没有办法让这个方法更有效,同时还返回我需要它做的事情

如果你可以将你的列表更改为一本
字典
,并将个人ID作为关键,那么这对你很有用。这将在
O(n)
中运行,而不是在
O(n^2)
中运行


这将允许您的代码处理任何希望使用默认Equals方法而不是自定义方法的内容。

您确定比较是瓶颈吗?我认为问题来自您在这一行中所做的搜索:

var matchingPerson = listB.FirstOrDefault(e => e.ID == personA.ID);
在这里,您正在执行一个日志复杂度为O(n)的搜索,它与
foreach
循环相结合,给出了O(n^2)的总复杂度。相反,您可以预先创建一个字典,这需要一些时间,但查找速度要快得多。字典应该以ID作为键,并且可以在
foreach
循环之前轻松创建:

var dictB = listB.ToDictionary(p => p.ID);
之后,您的查找速度会快得多,如下所示:

    Person matchingPerson;
    if (dictB.TryGetValue(personA.ID, out matchingPerson))
    {
        if (!personA.IsEqual(matchingPerson))
        {
            modifiedPeople.Add(personA);
        }
    }

你必须使用列表吗?如果你有这个人的身份证,你能不能把他们储存在字典之类的东西里?你真的需要把这些名单放在一起比较吗?如果对象已更新,为什么不在对象内跟踪并将其作为布尔属性公开(即`person.IsDirty`)?尽管我现在意识到
person.IsDirty
可能不是最好的命名约定…而且,不要在这里重新发明轮子,重写而不是编写自己的
IsEqual()
注意,您的“通常”处理对象集的方法非常不寻常。。。列表在几乎所有的集合操作中都非常糟糕-请参阅以获取指导…我认为最好也提到重写
Equals()
(最好给OP一些更好的实践)是的。我什么都没说只是因为你已经把它放在你的评论里了,但我会把它加在这里。哇!这是一个巨大的不同!太棒了,谢谢你。还有,是的,我知道我应该重写Equals()。我的同事已经为Equals添加了一个覆盖,因为他只想在比较id时返回true,而不关心属性。所以他的重写类似于:public override bool Equals(Person other){if(ID!=other.ID){return false;}return true;}显然,在我的例子中,我希望Equals专门比较属性。我真的不知道如何解决这个难题,所以我把我的方法作为一个单独的方法。你完全正确,第一个默认值确实是瓶颈,而不是比较器。我已经将其更改为从列表中生成一个字典(我确实需要该列表用于其他目的),甚至包括开销,查找速度也显著加快。如果可以的话,我会把你和迈克尔·夏普都列为公认的答案!
var dictB = listB.ToDictionary(p => p.ID);
    Person matchingPerson;
    if (dictB.TryGetValue(personA.ID, out matchingPerson))
    {
        if (!personA.IsEqual(matchingPerson))
        {
            modifiedPeople.Add(personA);
        }
    }