如何快速从第一组物体中不存在的第二组物体中取出物体?

时间:2015-04-25 12:40:03

标签: c#

我在两个数据库中有记录。这是第一个数据库中的实体:

public class PersonInDatabaseOne
{
    public string Name { get; set; }
    public string Surname { get; set; }
}

这是第二个数据库中的实体:

public class PersonInDatabaseTwo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

如何从第二个数据库中获取第一个数据库中不存在的记录(第一个名称和姓氏必须与第一个数据库中的不同)。现在我有类似的东西,但这很慢,太慢了:

List<PersonInDatabaseOne> peopleInDatabaseOne = new List<PersonInDatabaseOne>();
// Hear I generate objects but in real I take it from database:
for (int i = 0; i < 100000; i++)
{
    peopleInDatabaseOne.Add(new PersonInDatabaseOne { Name = "aaa" + i, Surname = "aaa" + i });
}


List<PersonInDatabaseTwo> peopleInDatabaseTwo = new List<PersonInDatabaseTwo>();
// Hear I generate objects but in real I take it from database:
for (int i = 0; i < 10000; i++)
{
    peopleInDatabaseTwo.Add(new PersonInDatabaseTwo { FirstName = "aaa" + i, LastName = "aaa" + i });
}
for (int i = 0; i < 10000; i++)
{
    peopleInDatabaseTwo.Add(new PersonInDatabaseTwo { FirstName = "bbb" + i, LastName = "bbb" + i });
}


List<PersonInDatabaseTwo> peopleInDatabaseTwoWhichNotExistInDatabaseOne = new List<PersonInDatabaseTwo>();

// BELOW CODE IS VERY SLOW:
foreach (PersonInDatabaseTwo personInDatabaseTwo in peopleInDatabaseTwo)
{
    if (!peopleInDatabaseOne.Any(x => x.Name == personInDatabaseTwo.FirstName && x.Surname == personInDatabaseTwo.LastName))
    {
        peopleInDatabaseTwoWhichNotExistInDatabaseOne.Add(personInDatabaseTwo);
    }
};

2 个答案:

答案 0 :(得分:4)

最快的方法取决于实体的数量,以及您已经拥有的索引。

  • 如果有一些实体,那么您已经拥有的功能会更好,因为对一小组的多次扫描所花费的时间少于创建HashSet个对象。

  • 如果您的所有实体都适合内存,最好的方法是从中构建HashSet,并使用Except,其中详细说明了@ alex.feigin。

  • 如果您无法负担加载内存中的所有实体,则需要根据比较密钥将它们分成块并将其加载到内存中并应用{{ 1}}方法反复。请注意,批量不能基于记录数,而是基于比较键。例如,加载名称以HashSet开头的所有实体,然后加载'A',依此类推。

  • 如果您已在其中一个数据库中的比较键(例如,在您的情况下,'B'FirstName)上有数据库的索引,则可以检索已排序的列表来自数据库。这将帮助您在排序列表上进行二进制搜索(http://en.wikipedia.org/wiki/Binary_search_algorithm)以进行比较。请参阅https://msdn.microsoft.com/en-us/library/w4e7fxsh(v=vs.110).aspx

  • 如果您已在两个数据库上的比较键上有数据库索引,则可以在O(n)中以可扩展的方式(任何数字)执行此操作记录)。您需要遍历两个列表并仅查找一次差异。有关详细信息,请参阅https://stackoverflow.com/a/161535/187996

答案 1 :(得分:1)

编辑:关于评论 - 使用真实模型和字典而不是简单集:

尝试将您的列表哈希到一个词典中以保存您的人物对象,作为键 - 尝试一个元组而不是一个名字1 == name2&amp;&amp; lname1 == lname2。

这可能看起来像这样:

// Some people1 and people2 lists of models already exist:
var sw = Stopwatch.StartNew();
var removeThese = people1.Select(x=>Tuple.Create(x.FirstName,x.LastName));
var dic2 = people2.ToDictionary(x=>Tuple.Create(x.Name,x.Surname),x=>x);
var result =  dic2.Keys.Except(removeThese).Select(x=>dic2[x]).ToList();
Console.WriteLine(sw.Elapsed);

我希望这会有所帮助。