2012-08-24 2 views
6

나는 Thing의 숫자가 값 유형 인 T1 f1T2 f2의 두 변수의 조합을 찾아서 자주 검색 할 필요가있는 List<Thing> things을 가지고 있습니다. 내가 지금하는 방식은 단순히 things.Where(t => t.Field1 == f1 && t.Field2 == f2)입니다. 그러나, 나는 그 조회의 수시로 극단적으로 많은 것을하고, 효과적인 방법을 필요로한다.중복 된 다차원 키를 지원하는 사전?

다행히도 things에는 요소가 제거되거나 추가 될 필요가 없으므로 작성시 목록을 구문 분석하고 Dictionary<T1, Lookup<T2, Thing>>에 추가 할 것을 고려했습니다. 그러나 이것은 특히 구문 분석을 추가 할 때 지저분 해집니다. 그리고 더 많은 밭을 찾아야한다면 정말 털이 나옵니다. 세 개의 입력란은 Dictionary<T1, Dictionary<T2, Lookup<T3, Thing>>>과 같습니다.

내 생각은 Lookup<Tuple<T1,T2,T3,...>,Thing>입니다. 그러나이 경우 Tuple이 참조 유형이기 때문에 키가 실제로 작동하는지 확신 할 수 없습니다.

Lookup<ValueType<T1,T2,T3,...>,Thing> things을 만들더라도 lookup 문은 things[new ValueType<T1,T2,T3,...>(f1, f2, f3, ...)]과 비슷할 것입니다. 꽤 못생긴 것입니다. (여전히 그 키를 신뢰할 수 있는지 확실하지 않습니다.)

해시 테이블의 성능 이점을 유지하는 더 세련된 솔루션이 있습니까? IEnumerable<Thing> found = things[f1, f2, f3, ...];과 같이 간단하게 입력 할 수 있습니다.

+1

메모리 데이터베이스에서 SQLite와 같은 것을 사용 해본 적이 있습니까? – CodingGorilla

+0

'존재하는 것'에 ID가 있는지 (ID, PrimaryKey 또는 기타)? –

+0

[C# 다중 키 일반 사전] (http://www.codeproject.com/Articles/32894/C-Multi-key-Generic-Dictionary) –

답변

3

Lookup<Tuple<T1,T2,T3,...>,Thing>를 인쇄합니다.

조회 구문을 덜보기 좋게하려면 형식 유추를 지원하는 Tuple.Create을 사용할 수 있습니다. 귀하의 코드는 things[Tuple.Create(f1, f2, f3, ...)]이됩니다. 너무 추한 경우 개별 값을 매개 변수로 사용하는 도우미 메서드를 추가하는 것은 간단합니다.

또한 키에 대한 고유 한 변경 불가능한 클래스 (또는 값 유형)를 만들므로 ItemX 대신 깨끗한 필드 이름을 얻을 수 있습니다. EqualsGetHashCode을 일관되게 무시하면됩니다.

+0

어쩌면 내가 뭔가를하고 있었다. 이것은 확실히 단순하고 깔끔한 솔루션처럼 보입니다. 나는 당신이 의미하는 바를 모르겠다 "그래서 당신은'ItemX' 대신 깨끗한 필드 이름을 얻는다. 그리고 어떻게 'Equals'와'GetHashCode'를 오버라이드합니까? 나는 그 구현이 어떻게 보일 것인가를 모른다. –

+1

'ItemX'는'Tuple' 클래스를 사용하면 발생합니다. 아이디어는 대신'Item1','Item2' 등보다 더 나은 속성 이름을 가진 자신의 클래스를 만드는 것입니다. – Oliver

+0

튜플은 많은 해쉬 콜리 션을 생성합니다. 그것은 열쇠를위한 좋은 후보자가 아닙니다. – Paparazzi

1

필드의 조합과 같은 종류의 해시 테이블을 키로 사용해 보셨습니까? 이것이 실용적인지 아닌지를 말할 수있는 데이터에 대해 충분히 알지 못합니다. 키는 고유해야 할 필요가 있기 때문입니다. 그러나 메모리에서 조회를 위해 해시 테이블을 사용하여 추가 또는 제거를 수행하지 않으므로 최대한 빨리 얻을 수 있습니다. 내가 바로 당신을 가지고있는 경우

+0

분명히 그는 튜플이 필드의 조합이고'Lookup'은 해시 테이블입니다. – CodesInChaos

1

, 당신은 TupleHashtable을 사용할 수 있습니다, 아래의 예 :

 // populate Hastable 
     var hash = new Hashtable();    
     var tuple = Tuple.Create("string", 1, 1.0); 
     hash.Add(tuple,tuple); 

     // search for item you want 
     var anotherTuple = Tuple.Create("string", 1, 1.0); 
     // result will be tuple declared above 
     var result = hash[anotherTuple]; 

더 복잡한 솔루션 (중복 키가 필요한 경우) :

public class Thing 
{ 
    public int Value1 { get; set; } 

    public double Value2 { get; set; } 

    public string Value3 { get; set; } 

    // preferable to create own Equals and GetHashCode methods 
    public Tuple<int, double> GetKey() 
    { 
     // create key on fields you want 
     return Tuple.Create(Value1, Value2); 
    } 
} 

사용

var t1 = new Thing() {Value1 = 1, Value2 = 1.0, Value3 = "something"}; 
var t2 = new Thing() {Value1 = 1, Value2 = 2.0, Value3 = "something"}; 
var hash = new [] { t1, t2 }.ToLookup(item => item.GetKey()); 

var criteria = new Thing() { Value1 = 1, Value2 = 2.0, value3 = "bla-bla-bla" }; 
var r = hash[criteria.GetKey()]; // will give you t1 
+0

중복 키가 없으며 비 일반 해시 테이블을 사용하는 이유는 무엇입니까? – CodesInChaos

+0

이 컬렉션에 동일한 항목이 포함되어 있다고 생각하지 않습니다. 'Hastable '- 코드 * 단순화에 사용됨 *. – user854301

+0

아쉽게도 내 요구 사항에 중복 키가 필요합니다. –

2

여러 개의 조회를 작성한 다음 교차하여 검색을 수행 할 수 있습니다 체스. 여기에 다소 과도하게 단순화 예이지만, 아이디어를 설명해야합니다

class Test { 
    public string A { get; set; } 
    public string B { get; set; } 
    public string C { get; set; } 
} 

var list = new List<Test> { 
    new Test {A = "quick", B = "brown", C = "fox"} 
, new Test {A = "jumps", B = "over", C = "the"} 
, new Test {A = "lazy", B = "dog", C = "quick"} 
, new Test {A = "brown", B = "fox", C = "jumps"} 
, new Test {A = "over", B = "the", C = "lazy"} 
, new Test {A = "dog", B = "quick", C = "brown"} 
, new Test {A = "fox", B = "jumps", C = "over"} 
, new Test {A = "the", B = "lazy", C = "dog"} 
, new Test {A = "fox", B = "brown", C = "quick"} 
, new Test {A = "the", B = "over", C = "jumps"} 
, new Test {A = "quick", B = "dog", C = "lazy"} 
, new Test {A = "jums", B = "fox", C = "brown"} 
, new Test {A = "lazy", B = "the", C = "over"} 
, new Test {A = "brown", B = "quick", C = "dog"} 
, new Test {A = "over", B = "jumps", C = "fox"} 
, new Test {A = "dog", B = "lazy", C = "the"} 
}; 
var byA = list.ToLookup(v => v.A); 
var byB = list.ToLookup(v => v.B); 
var byC = list.ToLookup(v => v.C); 
var all = byA["quick"].Intersect(byB["dog"]); 
foreach (var test in all) { 
    Console.WriteLine("{0} {1} {2}", test.A, test.B, test.C); 
} 
all = byA["fox"].Intersect(byC["over"]); 
foreach (var test in all) { 
    Console.WriteLine("{0} {1} {2}", test.A, test.B, test.C); 
} 

Tuple 무시 EqualsGetHashCode 때문에, 작동

quick dog lazy 
fox jumps over 
+0

당신이 검색하는 희귀 한 단어가 희귀 한 경우 빨리 할 수 ​​있습니다. 그렇지 않으면 느려질 수 있습니다. – CodesInChaos

+0

@CodesInChaos 사실입니다. 단어가 잘 분산되어 있지 않으면 속도가 훨씬 빨라질 것입니다. 비록 당신이 여전히 게시물의 상단에 설명 된 "전체 스캔"방법을 이길 것이라고 생각합니다. – dasblinkenlight

+0

이것에 대한 약간의 변형은 희귀 한 단어에 대한 검색을 사용하고 거기에서'Where'로 필터링하는 것입니다. 약간 더 빨라지고 메모리가 적을 수도 있습니다. – CodesInChaos

0

Linq Where 또는 Dictionary of Dictionaries는 아마 당신이 얻게 될 가장 예쁜 것이다. 그러나 그것은 당신이 당신의 데이터를 어떻게 조직하고 있는지에 대한 더 많은 질문 일 수 있습니다.

E.G. 이것은 사람들의 데이터에 접근하는 훌륭한 방법이 될 수 없습니다 :

people["FirstName"]["LastName"] 

보통 더 간단한 키를 사용하는 것이 좋습니다.

관련 문제