查找C#列表中是否存在值的最有效方法

时间:2013-04-17 11:58:15

标签: c# list

如果我有一个bool类型的列表,请在C#中。确定列表是否包含真值的最快方法是什么?我不需要知道真正价值的数量或位置。我只需知道一个是否存在。我将搜索许多非常大的列表。

9 个答案:

答案 0 :(得分:20)

只需使用bool trueInList = list.Contains(true);即可。这将循环列表,直到有true

为什么在这么简单的用例中你需要更快的东西?

答案 1 :(得分:7)

使用list.Contains(true)或list.Any(true)。 对于正常列表,两者都具有复杂度O(n)。由于Any()是一种扩展方法,需要调用委托,所以Contains()可能会更快一些。但是要确保我只是用大量的集合来测试它们。

答案 2 :(得分:5)

您可以使用Any()。

list.Any(b => b);

答案 3 :(得分:3)

试试这个:

var result = myBoolList.Any(i => i==true);

答案 4 :(得分:2)

这将是最快的方式:

static bool AnySet(List<bool> data)
{
    for (int i = 0; i < data.Count; ++i)
        if (data[i])
            return true;

    return false;
}

小心涉及Linq的答案。它们会慢一点,正如这个测试程序所展示的那样(事实上,Linq的速度要快12倍!

这也表明(至少在我的系统上)手动编码循环比List.Contains()快3.5倍。

我的电脑上的结果(Windows 8 x64,程序编译为x86)

Times in seconds

01.0994496 data.Any() list
01.1147795 data.Any() enumerable
00.1215951 hand-rolled loop
00.4240996 list.Contains()

我在几个系统上测试了这个,包括一台运行XP的5年旧笔记本电脑和一台装有Windows 8的新电脑,结果相似。

(不要忘记从RELEASE版本中做你的计时。)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            int size = 10000000;
            int count = 10;
            List<bool> data = new List<bool>(size);

            for (int i = 0; i < size; ++i)
                data.Add(false);

            var sw = Stopwatch.StartNew();

            for (int trial = 0; trial < 5; ++trial)
            {
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet1(data);

                Console.WriteLine(sw.Elapsed + " data.Any() list");
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet2(data);

                Console.WriteLine(sw.Elapsed + " data.Any() enumerable");
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet3(data);

                Console.WriteLine(sw.Elapsed + " hand-rolled loop");
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet4(data);

                Console.WriteLine(sw.Elapsed + " list.Contains()");

                Console.WriteLine();
            }
        }

        static bool AnySet1(List<bool> data)
        {
            return data.Any(b => b);
        }

        static bool AnySet2(IEnumerable<bool> data)
        {
            return data.Any(b => b);
        }

        static bool AnySet3(List<bool> data)
        {
            for (int i = 0; i < data.Count; ++i)
                if (data[i])
                    return true;

            return false;
        }

        static bool AnySet4(List<bool> data)
        {
            return data.Contains(true);
        }
    }
}

那么,为什么List.Contains()会慢一些呢?好吧,让我们用反射器来看看它的实现:

bool Contains(T item)
{
    if (item == null)
    {
        for (int j = 0x0; j < this._size; j++)
        {
            if (this._items[j] == null)
            {
                return true;
            }
        }
        return false;
    }
    EqualityComparer<T> comparer = EqualityComparer<T>.Default;
    for (int i = 0x0; i < this._size; i++)
    {
        if (comparer.Equals(this._items[i], item))
        {
            return true;
        }
    }
    return false;
}

啊哈!一切都揭晓了!它为每个元素调用comparer.Equals()。难怪它慢一点!


我还想提两件事:

  • 如果你真的想要最高速度,你应该使用普通数组而不是列表。
  • 为了获得最大可能的速度,您可以编写自己的BitArray版本,将bools存储为32位无符号整数的位。然后你可以真正地缩放它,每次检查32位,每个uint上只有一个简单的!= 0

答案 5 :(得分:1)

您使用Any(...)

list.Any(c => c == true);

或只是

list.Any(c => c);

答案 6 :(得分:1)

这个答案提供了一个不同的角度:为什么将bool存储在列表中?将它们存储为两个整数:int falseCount; int trueCount;

包含测试非常简单:trueCount > 0

假设您需要列表,请使用List.Contains,因为它直接搜索基础数组。

使用反射提取底层数组并在硬编码比较循环中搜索它会更快。您可以使用文字true来比较每个元素。你甚至可以展开循环或做不安全的代码技巧。

答案 7 :(得分:0)

bool val = false;
Foreach(bool val in listofvalue)
{
   val |= val;
}

if(val)
print "List contain true value"

else

print "List contain false value"

答案 8 :(得分:0)

您可以使用列表中的BinarySearch方法。

if(list.BinarySearch(true) > 0){...}