답변:
설명서 참조
List.Exist (오브젝트 메소드-MSDN)
List (T)에 지정된 조건 자에 의해 정의 된 조건과 일치하는 요소가 포함되어 있는지 확인합니다.
이것은 .NET 2.0 이후 LINQ 이전에 존재합니다. Predicate delegate 와 함께 사용 되지만 람다 식은 이전 버전과 호환됩니다. 또한 List만이 이것을 가지고 있습니다 (IList조차도 아닙니다)
IEnumerable.Any (확장 방법-MSDN)
시퀀스의 요소가 조건을 만족하는지 여부를 결정합니다.
이것은 .NET 3.5의 새로운 기능이며 Func (TSource, bool)를 인수로 사용하므로 람다 식 및 LINQ와 함께 사용됩니다.
행동에서, 이들은 동일합니다.
차이점은 Any는 IEnumerable<T>
System.Linq.Enumerable에 정의 된 모든 확장 방법이라는 것입니다 . 모든 IEnumerable<T>
인스턴스에서 사용할 수 있습니다 .
존재하는 확장 방법이 아닌 것 같습니다. 내 생각에 콜은 유형 List<T>
입니다. 그렇다면 Exists는 Any와 매우 유사한 기능을하는 인스턴스 방법입니다.
요컨대 , 방법은 본질적으로 동일합니다. 하나는 다른 것보다 더 일반적입니다.
TLDR; 성능면 Any
에서는 속도가 느린 것 같습니다 (거의 동시에 두 값을 모두 평가하도록 올바르게 설정하면)
var list1 = Generate(1000000);
var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
if (forceListEval != "sdsdf")
{
var s = string.Empty;
var start2 = DateTime.Now;
if (!list1.Exists(o => o == "0123456789012"))
{
var end2 = DateTime.Now;
s += " Exists: " + end2.Subtract(start2);
}
var start1 = DateTime.Now;
if (!list1.Any(o => o == "0123456789012"))
{
var end1 = DateTime.Now;
s +=" Any: " +end1.Subtract(start1);
}
if (!s.Contains("sdfsd"))
{
}
테스트 목록 생성기 :
private List<string> Generate(int count)
{
var list = new List<string>();
for (int i = 0; i < count; i++)
{
list.Add( new string(
Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
.Select(s =>
{
var cryptoResult = new byte[4];
new RNGCryptoServiceProvider().GetBytes(cryptoResult);
return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
})
.ToArray()));
}
return list;
}
10M 기록
"모두 : 00 : 00 : 00.3770377 기존 : 00 : 00 : 00.2490249"
5M 기록
"모두 : 00 : 00 : 00.0940094 기존 : 00 : 00 : 00.1420142"
1M 기록
"모두 : 00 : 00 : 00.0180018 기존 : 00 : 00 : 00.0090009"
500k로 (나는 또한 어느 것이 먼저 실행되는지와 관련된 추가 작업이 없는지 확인하기 위해 평가되는 순서를 뒤집 었습니다.)
"기존 : 00 : 00 : 00.0050005 모두 : 00 : 00 : 00.0100010"
100k 레코드
"기존 : 00 : 00 : 00.0010001 모두 : 00 : 00 : 00.0020002"
Any
2의 크기만큼 느려질 것 같습니다 .
편집 : 5M 및 10M 레코드의 경우 목록을 생성하는 방식을 변경하고 Exists
갑자기 Any
테스트하는 방식에 문제가 있음을 의미하는 것보다 느려졌습니다 .
새로운 테스트 메커니즘 :
private static IEnumerable<string> Generate(int count)
{
var cripto = new RNGCryptoServiceProvider();
Func<string> getString = () => new string(
Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
.Select(s =>
{
var cryptoResult = new byte[4];
cripto.GetBytes(cryptoResult);
return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
})
.ToArray());
var list = new ConcurrentBag<string>();
var x = Parallel.For(0, count, o => list.Add(getString()));
return list;
}
private static void Test()
{
var list = Generate(10000000);
var list1 = list.ToList();
var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
if (forceListEval != "sdsdf")
{
var s = string.Empty;
var start1 = DateTime.Now;
if (!list1.Any(o => o == "0123456789012"))
{
var end1 = DateTime.Now;
s += " Any: " + end1.Subtract(start1);
}
var start2 = DateTime.Now;
if (!list1.Exists(o => o == "0123456789012"))
{
var end2 = DateTime.Now;
s += " Exists: " + end2.Subtract(start2);
}
if (!s.Contains("sdfsd"))
{
}
}
Edit2 : 테스트 데이터 생성에 따른 영향을 제거하기 위해 파일에 모두 쓰고 이제 거기에서 읽습니다.
private static void Test()
{
var list1 = File.ReadAllLines("test.txt").Take(500000).ToList();
var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
if (forceListEval != "sdsdf")
{
var s = string.Empty;
var start1 = DateTime.Now;
if (!list1.Any(o => o == "0123456789012"))
{
var end1 = DateTime.Now;
s += " Any: " + end1.Subtract(start1);
}
var start2 = DateTime.Now;
if (!list1.Exists(o => o == "0123456789012"))
{
var end2 = DateTime.Now;
s += " Exists: " + end2.Subtract(start2);
}
if (!s.Contains("sdfsd"))
{
}
}
}
10M
"모두 : 00 : 00 : 00.1640164 기존 : 00 : 00 : 00.0750075"
5M
"모두 : 00 : 00 : 00.0810081 기존 : 00 : 00 : 00.0360036"
1M
"모두 : 00 : 00 : 00.0190019 기존 : 00 : 00 : 00.0070007"
500k
"모두 : 00 : 00 : 00.0120012 기존 : 00 : 00 : 00.0040004"
벤치마킹 에 대한 Matas의 답변 을 계속합니다 .
TL / DR : Exists ()와 Any ()는 똑같이 빠릅니다.
우선 : 스톱워치를 사용한 벤치마킹은 정확하지 않지만 ( 다른 주제 이지만 주제가 많은 series0ne의 답변 참조 ) DateTime보다 훨씬 정확합니다.
실제로 정확한 측정 값을 얻는 방법은 성능 프로파일 링을 사용하는 것입니다. 그러나 두 방법의 성능을 서로 측정하는 방법을 이해하는 한 가지 방법은 두 방법을 모두 로드 한 다음 가장 빠른 실행 시간을 비교하는 것입니다. 그 방법은, 정말 JITing 및 기타 노이즈가 우리에게 나쁜 판독을 제공 (그리고 그 중요하지 않습니다 않습니다 모두 처형 "하기 때문에,) 똑같이 misguiding 의미에서".
static void Main(string[] args)
{
Console.WriteLine("Generating list...");
List<string> list = GenerateTestList(1000000);
var s = string.Empty;
Stopwatch sw;
Stopwatch sw2;
List<long> existsTimes = new List<long>();
List<long> anyTimes = new List<long>();
Console.WriteLine("Executing...");
for (int j = 0; j < 1000; j++)
{
sw = Stopwatch.StartNew();
if (!list.Exists(o => o == "0123456789012"))
{
sw.Stop();
existsTimes.Add(sw.ElapsedTicks);
}
}
for (int j = 0; j < 1000; j++)
{
sw2 = Stopwatch.StartNew();
if (!list.Exists(o => o == "0123456789012"))
{
sw2.Stop();
anyTimes.Add(sw2.ElapsedTicks);
}
}
long existsFastest = existsTimes.Min();
long anyFastest = anyTimes.Min();
Console.WriteLine(string.Format("Fastest Exists() execution: {0} ticks\nFastest Any() execution: {1} ticks", existsFastest.ToString(), anyFastest.ToString()));
Console.WriteLine("Benchmark finished. Press any key.");
Console.ReadKey();
}
public static List<string> GenerateTestList(int count)
{
var list = new List<string>();
for (int i = 0; i < count; i++)
{
Random r = new Random();
int it = r.Next(0, 100);
list.Add(new string('s', it));
}
return list;
}
위의 코드를 (다시 1000을 4 번 실행 한 후 Exists()
와 Any()
1 개 000 000 요소가있는 목록을),이 방법은 거의 동일하게 빠른 것을 볼 어렵지 않다.
Fastest Exists() execution: 57881 ticks
Fastest Any() execution: 58272 ticks
Fastest Exists() execution: 58133 ticks
Fastest Any() execution: 58063 ticks
Fastest Exists() execution: 58482 ticks
Fastest Any() execution: 58982 ticks
Fastest Exists() execution: 57121 ticks
Fastest Any() execution: 57317 ticks
가 있습니다 약간의 차이는 있지만, 배경 잡음에 의해 설명 할 수없는 너무 작은 차이입니다. 내 생각 엔 한 10 000 100 000을한다면 있다는 것 Exists()
및 Any()
대신에, 그 약간의 차이가 다소 사라질 것이다.