我有一个子查询,我需要知道至少有一个项目存在,并且所有存在的项目都是真的。
现在我正在做一个Any和All,但是这个只是一个All或者只是一个Any(因为它做了两次),这个速度非常慢。
我正在寻找一种方法来做AnyAll :)效率会更高。
有什么想法吗?
答案 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;
}