【问题标题】:When searching for an item in a generic list should I use LINQ or Contains?在通用列表中搜索项目时,我应该使用 LINQ 还是包含?
【发布时间】:2010-07-28 15:45:10
【问题描述】:

我有一个通用的List,我必须在这个列表中找到一个特定的字符串。您能否告诉我以下哪种方法最好?

if (strlist.Contains("Test"))
{
    // String found
}

string res = (from d in strlist where d == "Test" select d).SingleOrDefault();

if (res == "Test")
{
    //found
}

请考虑从数据库中填充的列表可能非常大。非常感谢您对此的想法。

【问题讨论】:

  • 必填项:您是否进行过测试和测量?

标签: c# .net linq search


【解决方案1】:

如果您有 List<string>(甚至是 IEnumerable<string>)并且 Contains 满足您的需求,请使用 Contains。

如果您需要一些 Contains 未提供的额外处理,我建议使用 Any():

if(strList.Any(s => s.StartsWith("Tes"))
{
    // Found
}

【讨论】:

  • Exacaly,编译器无论如何都会对其进行优化,并且带有 Contains 的 sn-p 看起来要好得多;)
【解决方案2】:

如果有多个匹配项,这两种方法的行为会有所不同;第一个会返回 true,第二个会抛出异常。

要更正此问题,请将 SingleOrDefault 更改为 FirstOrDefault

要回答这个问题,如果您正在搜索完全匹配,则应致电 Contains,如果不是,则应致电 Any

例如:

if (strings.Contains("SomeString", StringComparer.OrdinalIgnoreCase))

if (strings.Any(s => s.StartsWith("b"))

【讨论】:

  • 其实第二个不会。你在想Single
  • @ChaosPandion:错了。 SingleOrDefault 只会在有 个匹配项时返回 default(T)。否则,它将与FirstOrDefault 相同。
  • 我知道你真的不应该从文本中读取情感意图,但哎哟。
  • SingleOrDefault 如果您返回多行而不是仅一行或无,将返回错误。
  • @Jonathan:我就是这个意思。
【解决方案3】:

您真的应该使用HashSet<string>,因为Contains 的性能要好得多。现在,如果您需要将列表用于其他操作,您可以简单地同时使用两者。

var list = BuildListOfStrings();
var set = new HashSet<string>(list);

if (set.Contains("Test"))
{
    // ...
}

现在您可以通过O(1) 操作在集合中查找项目。

测试

static void Main(string[] args)
{
    var lst = GenerateStrings().Take(5000000).ToList();
    var hsh = new HashSet<string>(lst);
    var found = false;
    var count = 100;
    var sw = Stopwatch.StartNew();

    for (int i = 0; i < count; i++)
    {
        hsh = new HashSet<string>(lst);
    }
    Console.WriteLine(TimeSpan.FromTicks(sw.ElapsedTicks / count));

    sw = Stopwatch.StartNew();
    for (int i = 0; i < count; i++)
    {
        found = lst.Contains("12345678");
    }
    Console.WriteLine(TimeSpan.FromTicks(sw.ElapsedTicks / count));

    sw = Stopwatch.StartNew();
    for (int i = 0; i < count; i++)
    {
        found = hsh.Contains("12345678");
    }
    Console.WriteLine(TimeSpan.FromTicks(sw.ElapsedTicks / count));

    Console.WriteLine(found);
    Console.ReadLine();
}

private static IEnumerable<string> GenerateStrings()
{
    var rnd = new Random();
    while (true)
    {
        yield return rnd.Next().ToString();
    }
}

结果

0.308438 秒 0.0197868 秒 0.0 秒

那么这告诉我们什么?如果您对Contains 进行少量调用,请使用List&lt;string&gt;,否则使用HashSet&lt;string&gt;

【讨论】:

  • 如果他需要保持顺序,他不应该。
  • @SLaks - 你显然是对的,但他们提到列表可能非常大的事实意味着这将显着提高性能。由于string 是一个引用类型,他们可以简单地保留一个List&lt;string&gt; 用于其他操作,而不必担心过多的内存使用。
  • 假设列表的包含是固定的,并且重复执行此任务。构建一个临时 hashSet 只是为了执行一个 Contain,会变慢然后只在 List 上调用 Contains,
  • 一开始就必须构造 HashSet 不会对性能造成影响吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-13
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 2020-08-20
  • 2011-01-12
  • 2010-11-09
相关资源
最近更新 更多