搜索不同的通用List <t>以查找常见项目,如何更好地完成此操作?</t>

时间:2014-09-03 09:12:40

标签: c# .net algorithm

我有一个模拟一个人的课程;除了通常的属性之外是该人的手机号码

public class Person
{
    // Other properties elided here for brevity's sake
    public string PersonMobileNumber { get; set; }
}

向该人发送他们可能会或可能不会回复的短信。我已经定义了一条消息:

public class SmsMessage
{
    public string NumberFrom { get; set;}
    public string NumberTo { get; set;}
    public string MessageContent { get; set; }
    public DateTime DateTimeReceived { get; set; }
}

现在我想看到的是谁回复了我的短信。

简单地说,您有许多短信(List<SmsMessage>)和一些人(List<Person>

在旧的LINQ之前的日子里,我只需要foreached通过两个集合,在第一个集合中有一个foreach,但我认为LINQ应该能够在这里帮助我。我提出的相关陈述如下:

List<Person> peopleThatResponded =
    people.Where(p => smsMessages.Exists(s => s.NumberFrom == p.MobileNumber)).ToList();

只是觉得这对小型数据集很有用(这是基于调试它并观察代码中的循环)但我确信有一种更高效的方法可以做到这一点。 FWIW我可以完全控制类定义,并可以进行任何需要进行的更改。

2 个答案:

答案 0 :(得分:2)

更加高效的方式是加入他们:

var peopleThatResponded = from pers in people
                          join sms in smsMessages
                          on pers.PersonMobileNumber equals sms.NumberFrom 
                          select pers;
List<Person> peopleListThatResponded = peopleThatResponded.ToList();

Why is LINQ JOIN so much faster than linking with WHERE?

但如果他们多次回复,那会重复人们。另一种方法是使用HashSet<string>代替更有效的列表。

var smsNumbers = new HashSet<string>(smsMessages.Select(sms => sms.NumberFrom));
List<Person> peopleThatResponded = people
    .Where(p => smsNumbers.Contains(p.PersonMobileNumber)).ToList();

答案 1 :(得分:1)

Exists中使用where是一个O(n * m)解决方案,因此随着人数或消息的增加,这将会明显变慢。

您可以将现有数字放在哈希集中,然后将人与之匹配。这将是一个O(n + m)解决方案,所以它可以很好地扩展:

HashSet<string> numbers =
  new HashSet<string>(smsMessages.Select(m => m.NumberFrom));

List<Person> peopleThatResponded =
  people.Where(p => numbers.Contains(p.MobileNumber)).ToList();