Linq:All有价值设定,至少有一个有价值吗?

时间:2014-06-11 22:51:29

标签: performance linq entity-framework

我有一个子查询,我需要知道至少有一个项目存在,并且所有存在的项目都是真的。

现在我正在做一个Any和All,但是这个只是一个All或者只是一个Any(因为它做了两次),这个速度非常慢。

我正在寻找一种方法来做AnyAll :)效率会更高。

有什么想法吗?

4 个答案:

答案 0 :(得分:1)

这是三个测试。我认为#2是最快的,然后是#1,最后是#3。

    List<BooBoo> list1; // empty
    List<BooBoo> list2; // false, then lots of true
    List<BooBoo> list3; // lots of true, false
    List<BooBoo> list4; // one true
    List<BooBoo> list5; // lots of true
    List<BooBoo> list6; // one false
    List<BooBoo> list7; // lots of false
    private void button1_Click(object sender, EventArgs e)
    {
        MakeLists();

        long span1 = RunTest1(200000);
        long span2 = RunTest2(200000);
        long span3 = RunTest3(200000);
    }

    private long RunTest1(long numTimes)
    {
        DateTime time1 = DateTime.Now;
        for (int count = 0; count < numTimes; count++)
        {
            bool b1 = IsItGood1(list1);
            bool b2 = IsItGood1(list2);
            bool b3 = IsItGood1(list3);
            bool b4 = IsItGood1(list4);
            bool b5 = IsItGood1(list5);
            bool b6 = IsItGood1(list6);
            bool b7 = IsItGood1(list7);
        }
        DateTime time2 = DateTime.Now;
        TimeSpan span = time2 - time1;
        return span.Ticks;
    }
    private bool IsItGood1(List<BooBoo> list)
    {
        return (list.Count > 0) && (list.FirstOrDefault(b => !b.BooMe) == null); // false
    }
    private long RunTest2(long numTimes)
    {
        DateTime time1 = DateTime.Now;
        for (int count = 0; count < numTimes; count++)
        {
            bool b1 = IsItGood2(list1);
            bool b2 = IsItGood2(list2);
            bool b3 = IsItGood2(list3);
            bool b4 = IsItGood2(list4);
            bool b5 = IsItGood2(list5);
            bool b6 = IsItGood2(list6);
            bool b7 = IsItGood2(list7);
        }
        DateTime time2 = DateTime.Now;
        TimeSpan span = time2 - time1;
        return span.Ticks;
    }
    private bool IsItGood2(List<BooBoo> list)
    {
        if (list.Count == 0) return false;
        foreach (BooBoo boo in list)
        {
            if (!boo.BooMe) return false;
        }
        return true;
    }
    private long RunTest3(long numTimes)
    {
        DateTime time1 = DateTime.Now;
        for (int count = 0; count < numTimes; count++)
        {
            bool b1 = IsItGood3(list1);
            bool b2 = IsItGood3(list2);
            bool b3 = IsItGood3(list3);
            bool b4 = IsItGood3(list4);
            bool b5 = IsItGood3(list5);
            bool b6 = IsItGood3(list6);
            bool b7 = IsItGood3(list7);
        }
        DateTime time2 = DateTime.Now;
        TimeSpan span = time2 - time1;
        return span.Ticks;
    }
    private bool IsItGood3(List<BooBoo> list)
    {
        return list.Any() && list.All(i => i.BooMe);
    }
    private void MakeLists()
    {
        #region make lists
        // at least one item, all true
        list1 = new List<BooBoo>(); // empty

        list2 = new List<BooBoo>();
        list2.Add(new BooBoo { BooMe = false });
        list2.Add(new BooBoo { BooMe = true });
        list2.Add(new BooBoo { BooMe = true });
        list2.Add(new BooBoo { BooMe = true });
        list2.Add(new BooBoo { BooMe = true });
        list2.Add(new BooBoo { BooMe = true });
        list2.Add(new BooBoo { BooMe = true });

        list3 = new List<BooBoo>();
        list3.Add(new BooBoo { BooMe = true });
        list3.Add(new BooBoo { BooMe = true });
        list3.Add(new BooBoo { BooMe = true });
        list3.Add(new BooBoo { BooMe = true });
        list3.Add(new BooBoo { BooMe = true });
        list3.Add(new BooBoo { BooMe = true });
        list3.Add(new BooBoo { BooMe = false });

        list4 = new List<BooBoo>();
        list4.Add(new BooBoo { BooMe = true });

        list5 = new List<BooBoo>();
        list5.Add(new BooBoo { BooMe = true });
        list5.Add(new BooBoo { BooMe = true });
        list5.Add(new BooBoo { BooMe = true });
        list5.Add(new BooBoo { BooMe = true });
        list5.Add(new BooBoo { BooMe = true });
        list5.Add(new BooBoo { BooMe = true });
        list5.Add(new BooBoo { BooMe = true });

        list6 = new List<BooBoo>();
        list6.Add(new BooBoo { BooMe = false });

        list7 = new List<BooBoo>();
        list7.Add(new BooBoo { BooMe = false });
        list7.Add(new BooBoo { BooMe = false });
        list7.Add(new BooBoo { BooMe = false });
        list7.Add(new BooBoo { BooMe = false });
        list7.Add(new BooBoo { BooMe = false });
        list7.Add(new BooBoo { BooMe = false });
        list7.Add(new BooBoo { BooMe = false });
        #endregion
    }

答案 1 :(得分:0)

为什么不只计算项目,然后寻找至少一个不真实的项目:

类BooBoo {public bool BooMe {get;组; }}

public static void Run(){

List<BooBoo> list = new List<BooBoo>();

bool isGood1 = (list.Count > 1) && (list.FirstOrDefault(b => !b.BooMe) == null); // false

list.Add(new BooBoo { BooMe = false });

bool isGood2 = (list.Count > 1) && (list.FirstOrDefault(b => !b.BooMe) == null); // false

list.Add(new BooBoo { BooMe = true });

bool isGood3 = (list.Count > 1) && (list.FirstOrDefault(b => !b.BooMe) == null); // false

list.Clear();
list.Add(new BooBoo { BooMe = true });
list.Add(new BooBoo { BooMe = true });

bool isGood4 = (list.Count > 1) && (list.FirstOrDefault(b => !b.BooMe) == null);  // true

}

答案 2 :(得分:0)

简短版本:没有比Any和All更好的方法。

我尝试过使用一个concat(在SQL中使用union),然后使用let语句执行any和all,但它比在每个表上执行任何操作要慢,然后是alls。最快的方法是这样的:

from q in query 

let someSubQuery = (from s in query.SubQuery where <filter> select s)
let someSubQuery2 = (from s in query.SubQuery2 where <filter> select s)

where (someSubQuery.Any() || someSubQuery2.Any()) && someSubQuery.All(a => a.Boolean) && someSubQuery2.All(a => a.Boolean)

select q

我还尝试在子查询中进行内部选择以查找它自己的匹配,但它也非常慢。

据我所知,还没有内置的T-SQL功能可以提供帮助。对于布尔运算符的逆,All只是一个NOT EXISTS,因此必须执行NOT EXISTS和EXISTS以确保至少存在一个true。我希望我能找到一种可以直接优化这个查询的SQL语法,然后我可以使用TVF或存储过程在服务器上进行查询并将它们暴露给实体框架,但是在做了大量研究之后就出现了没有这样的优化是可能的。

查询优化器似乎在优化它时做得相对较好,但它仍然相当昂贵。

长话短说,如果你需要这样做,做一个All和Any,这是最快的方法。所有其他方法的数量级都要慢一些。

答案 3 :(得分:0)

/// <summary>
/// Same behavior as "enumerable.All()" but returns false for an empty enumerable instead of true. 
/// Does this while avoiding the double traversal of the enumerable caused by the usual
/// pattern of calling "enumerable.Any() && enumerable.All()".
/// </summary>
/// <typeparam name="T">The element type of the enumerable.</typeparam>
/// <param name="enumerable">The enumerable for which to test and get a single item.</param>
/// <param name="predicate">The test to run on all elements of the enumerable.</param>
/// <returns>True if the enumerable had at least one element and all elements tested true for the predicate.</returns>
public static bool AllWithAtLeastOne<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
    IEnumerator<T> enumerator = enumerable.GetEnumerator();
    if (enumerator.MoveNext())
    {
        T singleElement = enumerator.Current;
        bool result = predicate(singleElement);
        while (result && enumerator.MoveNext())
        {
            singleElement = enumerator.Current;
            result = predicate(singleElement);
        }
        return result;
    }
    return false;
}