包含列表太慢,如何改进?

时间:2015-12-03 09:45:12

标签: c# linq list

我有一个对象列表,我希望将其减少到仅包含属于单独列表的属性的对象。

List1是一个简单字符串列表。

List2是包含两个字符串属性的对象列表; A和B.

应删除List1中不存在A B的所有项目。

此过程非常依赖于时间,需要尽可能快。 目前我有以下实施方式;

var List1 = new List<String>() {"Around", "9000", "strings"}; //List of about 9000 strings
var List2 = databaseList.ToList(); //Around 2.5 million objects

var reducedList = new HashSet<Object>();            
foreach (var item in List2)
{
    if(List1.Contains(item.A) && List1.Contains(item.B))
    {
        reducedList.Add(item);
    }
}

此过程大约需要7秒钟才能完成,这对我目前的要求来说太慢了。

我尝试使用LINQ运行它,但是给出相同的结果,大约7秒。

var reducedList = List2.Where(r => List1.Contains(r.A)).Where(r => List1.Contains(r.B)).ToList();

有什么建议我可以做些什么来改善这个?

修改 我无法在SQL方面做到这一点,因为我需要比较的9000个字符串不能“翻译”到SQL查询中,但会超过我们的SQL Server中允许的允许2100输入参数设置。

6 个答案:

答案 0 :(得分:3)

我没有尝试过,但可能会提高性能。

var List1 = new List<String>() {"Around", "9000", "strings"};
var List2 = databaseList.ToList(); //Around 2.5 million objects

var reducedList = List2.RemoveAll(i => !List1.Contains(i.A) && !List1.Contains(i.B)).ToList();

答案 1 :(得分:2)

首先,让我们更快地查找第一个列表:

var sought = new HashSet<String>() {"Around", "9000", "strings"};

如果你只是想要迭代它,为什么还要在内存中创建列表呢?除非您打算将List2用于其他目的,否则它没有做任何事情。

foreach (var item in databaseList)
{
  if(sought.Contains(item.A) && sought.Contains(item.B))
  {
    reducedList.Add(item);
  }
}

同时将reducedList哈希列表正确键入new HashList<TheActualTypeOfTheItemsHere>

如果该类型未实现IEquatable<T>,则添加该实现。如果那是不可能的,那么创建一个适当的IEqualityComparer<T>并在reducedList的构造函数中使用它。

答案 2 :(得分:0)

正如@Ondrej Svejdar指出的那样,如果databaseList来自EntityFramework,那么你不应该调用ToList(),因为它会进行数据库查询,返回250万条记录

var reducedList = databaseList
                 .Where(r => List1.Contains(r.A) && List1.Contains(r.B))
                 .ToList();

如果List1来自数据库(我希望9000是手动构建的大数字),那么请考虑使用join运算符。

答案 3 :(得分:0)

您的数据库版本可能是个问题: 参考:Slower sqlite 由于我不知道你使用的是什么DB,这可能是“无用的”#34;。但是看看你的数据库是否有最新版本,看看它有多快。在另一台PC /浏览器/手机上测试你的程序,看看你是否得到相同的结果。

现在你应该找到确实花费很长时间的东西。尝试删除你的if语句,看看速度是否有所改善。如果它没有改进,那就是查询速度是一个问题。如果是这样,请尝试以您不需要使用的方式查询您的数据库。

答案 4 :(得分:0)

您可以尝试在对象上实现IEquatable,因为这是Contains将调用以查看对象是否在列表中的方法

有关详细信息,请参阅此post

答案 5 :(得分:0)

List1通常有多大?如果它是您样本中的小列表,那么保留列表就可以了。如果情况并非如此,那么使用HashSet可能会获得更好的结果。

我认为真正的游戏规则改变者是避免使用250万个对象加载List2,以便稍后过滤它们。如果databaseList是某种类似于DbSet的IEnumerable,那么你可能会得到更好的结果:

var List1 = new List<String>() {"Around", "9000", "strings"};
var reducedList = (from item in databaseList
                   where List1.Contains(item.A) && List1.Contains(item.B)
                   select item).ToList();

对缩小列表使用HashSet只会减慢插入速度。如果您使用它来避免重复,或者为了加快后续查找,那么您应该保留它。否则List会更好。