.NET 2에서 고유 한 세트를 생성하는 가장 빠른 방법은 무엇입니까?
-
04-07-2019 - |
문제
나는 본질적으로 이름 값 쌍의 들쭉날쭉 한 배열이 있습니다. 이것으로부터 고유 한 이름 값 세트를 생성해야합니다. 들쭉날쭉 한 배열은 약 86,000 x 11 값입니다. 이름 값 쌍 (단일 문자열 "이름 = value"또는 Specialized Class와 같은 특수 클래스)을 저장하는 방법은 중요하지 않습니다.
추가 정보: 40 개의 별개의 이름과 더 많은 수의 별개의 값이 있습니다.
C# 및 .NET 2.0을 사용하고 있습니다 (성능이 너무 나쁘기 때문에 전체 제지 배열을 SQL 데이터베이스로 밀고 선택하는 것이 더 낫다고 생각합니다).
아래는 다음을 사용하는 현재 코드입니다.
List<List<KeyValuePair<string,string>>> vehicleList = retriever.GetVehicles();
this.statsLabel.Text = "Unique Vehicles: " + vehicleList.Count;
Dictionary<KeyValuePair<string, string>, int> uniqueProperties = new Dictionary<KeyValuePair<string, string>, int>();
foreach (List<KeyValuePair<string, string>> vehicle in vehicleList)
{
foreach (KeyValuePair<string, string> property in vehicle)
{
if (!uniqueProperties.ContainsKey(property))
{
uniqueProperties.Add(property, 0);
}
}
}
this.statsLabel.Text += "\rUnique Properties: " + uniqueProperties.Count;
해결책
0.34 초 안에 실행됩니다 9 분 이상
문제는 keyvaluepair structs를 비교할 때입니다. 비교 대상을 작성하고 사전에 인스턴스를 전달하여 주변에서 작업했습니다.
내가 결정할 수있는 것에서 keyvaluepair.gethashCode ()는 해시 코드를 반환합니다. Key
객체 (이 예에서 가장 고유 한 객체).
사전은 각 항목의 추가 (및 확인)를 추가 (및 확인)에 따라 Equals 및 gethashcode 함수를 모두 사용하지만 해시 코드가 덜 고유 할 때 평등 함수에 의존해야합니다.
보다 독특한 gethashcode 함수를 제공함으로써, 그것은 동등한 기능을 훨씬 덜 자주 발췌합니다. 또한 덜 고유 한 값을 덜 고유 한 값을 비교하기 위해 평등 함수를 최적화했습니다.
86,000 * 고유 한 특성을 가진 11 개의 항목은 아래의 비교 객체를 사용하여 0.34 초 안에 실행됩니다 (비교 객체가 없으면 9 분 22 초가 소요됨)
도움이 되었기를 바랍니다 :)
class StringPairComparer
: IEqualityComparer<KeyValuePair<string, string>>
{
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return x.Value == y.Value && x.Key == y.Key;
}
public int GetHashCode(KeyValuePair<string, string> obj)
{
return (obj.Key + obj.Value).GetHashCode();
}
}
편집하다: 단지 하나의 문자열이라면 (keyvaluepair 대신, String = name+value)는 약 2 배 빠릅니다. 그것은 좋은 intresting 문제이고 나는 보냈습니다. faaaaaar 너무 많은 시간 (그래도 조금 조용히 배웠 어)
다른 팁
각 키/값 쌍과 생성하는 고유 한 값 사이에 특정 상관 관계가 필요하지 않은 경우 Guid 만 사용할 수 있습니까? 이 문제는 현재 '키'가이 들쭉날쭉 한 배열에서 고유하지 않다고 가정합니다.
Dictionary<System.Guid, KeyValuePair<string, string>> myDict
= new Dictionary<Guid, KeyValuePair<string, string>>();
foreach of your key values in their current format
myDict.Add(System.Guid.NewGuid(), new KeyValuePair<string, string>(yourKey, yourvalue))
필요한 것을 저장하는 것처럼 들리지만 Guid와 원래의 의미 사이에 의미 론적 관계가 없기 때문에 어떻게 데이터를 철회 할 것인지 모르겠습니다.
질문에 더 많은 정보를 제공 할 수 있습니까?
keyvaluepair를 래퍼 클래스로 사용한 다음 세트를 만들기 위해 사전을 만듭니다. 또는 평등과 gethashcode를 무시하는 자신의 래퍼를 구현하십시오.
Dictionary<KeyValuePair, bool> mySet;
for(int i = 0; i < keys.length; ++i)
{
KeyValuePair kvp = new KeyValuePair(keys[i], values[i]);
mySet[kvp] = true;
}
a를 사용하는 대신 Dictionary
확장하지 않는 이유는 무엇입니까? KeyedCollection<TKey, TItem>
? 문서에 따르면 :
키가 값에 포함 된 컬렉션의 추상 기본 클래스를 제공합니다.
그런 다음을 무시해야합니다 protected TKey GetKeyForItem(TItem item)
기능. 하이브리드 사이입니다 IList<T>
그리고 IDictionary<TKey, TValue>
나는 그것이 매우 빠를 가능성이 높다고 생각합니다.
어때요 :
Dictionary<NameValuePair,int> hs = new Dictionary<NameValuePair,int>();
foreach (i in jaggedArray)
{
foreach (j in i)
{
if (!hs.ContainsKey(j))
{
hs.Add(j, 0);
}
}
}
IEnumerable<NameValuePair> unique = hs.Keys;
물론 C# 3.0, .NET 3.5를 사용하는 경우 :
var hs = new HashSet<NameValuePair>();
hs.UnionWith(jaggedArray.SelectMany(item => item));
트릭을 할 것입니다.
코드를 프로파일 링 했습니까? Foreach 루프가 병목 현상이 아니며 Retriver.getvehicles ()가 아닌가?
나는 리트리버를 가짜로 만들고 86.000 x 11 값을 반환하도록하는 작은 테스트 프로젝트를 만들었습니다. 첫 번째 시도는 5 초에 실행되어 포함 된 데이터가 생성되었습니다.
첫 번째 키가 "0#0"이고 마지막 "85999#10"인 키와 값 모두에 대해 동일한 값을 사용했습니다.
그런 다음 Guids로 전환했습니다. 동일한 결과.
그런 다음 다음과 같이 키를 더 길게 만들었습니다.
var s = Guid.NewGuid().ToString();
return s + s + s + s + s + s + s+ s + s + s;
이제 거의 10 초가 걸렸습니다.
그런 다음 열쇠를 미친 듯이 길게 만들고 메모리 예외를 얻지 못했습니다. 내 컴퓨터에 스왑 파일이 없으므로 즉시이 예외를 얻었습니다.
열쇠는 얼마나 걸립니까? 가상 메모리 소비가 성능 저하의 이유입니까?