2012-12-23 2 views
3

은 좋아 날 내가 뭔가를하는 것입니다 대상이 될 것입니다(발> = 발은 <=)

를 달성하기 위해 원하는 것을 명확하게 설명 할 수 그래서이 객체가 같은 500000 개 기록처럼 가질 것이다 SQL Server 테이블처럼

BigInt parameter1 
BigInt parameter2 
string parameter3 

이 매개과 매개 모두

(SQL 서버 테이블의 기본 키 같은) 인덱스를 구성하는 것입니다 - 아래의 데이터를 포함 위 그리고 나는 빨리 찾아 본다. 이 객체에서와 같이

return parameter3 where parameter1 <= value and value <= parameter2 

어떻게 사용할 수 있습니까?

지금까지 나는이 시도하고 나 또한 유래에 많은 질문을 검색하고 그들 중 누구도 정수 키에서 운영자 사이의 대상으로하지

DataView.RowFilter = super slow 
static Dictionary<Int64, KeyValuePair<Int64, string>> = slower than database query 
Database query = where parameter1 & parameter2 composes primary key = slow since i need to make over 500000 query. 

그들은 느리다. 그것들은 모두 다중 문자열 키입니다.

는 C# 4.0

+0

왜 임베디드 DB 엔진을 사용하지 않습니까? –

+0

@DavidHeffernan 네, 제가 사용하고있는 것입니다. 그러나 RAM 메모리의 객체와 비교할 때 실제로 느립니다. 그러나 아직 적절한 방법을 찾지 못했습니다. 예를 들어 단일 키인 경우 사전은 500000 개의 쿼리를 수행 할 때 데이터베이스를 쿼리하는 것보다 수천 배 더 빠릅니다. – MonsterMMORPG

+0

좋은 임베디드 DB는 모든 것을 RAM에 저장합니까? 어떤 DB를 사용하고 있습니까? –

답변

1

신속하고 더러운 스케치 :

public class GeoIp 
{ 
    private class GeoIpRecord 
    { 
     public long StartIp; 
     public long EndIp; 
     public string Iso; 
    } 

    private class GeoIpRecordComparer: IComparer<GeoIpRecord> 
    { 
     public int Compare(GeoIpRecord x, GeoIpRecord y) 
     { 
      return x.StartIp.CompareTo(y.StartIp); 
     } 
    } 

    private List<GeoIpRecord> geoIp; 
    private IComparer<GeoIpRecord> comparer; 

    public GeoIp() 
    { 
     this.geoIp = new List<GeoIpRecord>(500000) 
      { 
       new GeoIpRecord { StartIp = 1, EndIp = 2, Iso = "One" }, 
       new GeoIpRecord { StartIp = 3, EndIp = 5, Iso = "Three" }, 
       new GeoIpRecord { StartIp = 6, EndIp = 6, Iso = "Six" }, 
       new GeoIpRecord { StartIp = 7, EndIp = 10, Iso = "Seven" }, 
       new GeoIpRecord { StartIp = 15, EndIp = 16, Iso = "Fifteen" }, 
      }; 
     this.comparer = new GeoIpRecordComparer(); 
    } 

    public string GetIso(long ipValue) 
    { 
     int index = this.geoIp.BinarySearch(new GeoIpRecord() { StartIp = ipValue }, this.comparer); 

     if (index < 0) 
     { 
      index = ~index - 1; 
      if (index < 0) 
      { 
       return string.Empty; 
      } 
     } 

     GeoIpRecord record = this.geoIp[index]; 

     if (record.EndIp >= ipValue) 
     { 
      return record.Iso; 
     } 
     else 
     { 
      return string.Empty; 
     } 
    } 
} 
,363,210

그리고 솔루션을 확인 코드 :

GeoIp geoIp = new GeoIp(); 
var iso1 = geoIp.GetIso(1); // One 
var iso2 = geoIp.GetIso(2); // One 
var iso3 = geoIp.GetIso(3); // Three 
var iso4 = geoIp.GetIso(4); // Three 
var iso5 = geoIp.GetIso(5); // Three 
var iso6 = geoIp.GetIso(6); // Six 
var iso7 = geoIp.GetIso(7); // Seven 
var iso11 = geoIp.GetIso(11); // 
var iso15 = geoIp.GetIso(15); // Fifteen 
var iso17 = geoIp.GetIso(17); // 

목록이이 정렬 된 데이터로 가득합니다.

List.BinarySearch Method (T, IComparer)

1

나는 범위가 겹치는 [것을] 생각하지 않습니다.

이 문제를 큰 거래를 단순화 오히려 두 가지 차원의 검색을 수행하는 것보다, 당신이 당신의 목록을 정렬 할 수 있습니다,이 같은 한 차원 이진 검색을 수행

여기
var data = new List<Tuple<long,long,string>>(TotalCount); 
var cmp = new TupleComparer(); 
data.Sort(cmp); 
long item = ... // The item to be searched 
var pos = data.BinarySearch(Tuple.Create(item, long.MinValue, String.Empty), cmp); 
// It appears that your data has only non-empty strings, so it is guaranteed that 
// pos is going to be negative, because Item3, the last tie-breaker, will be smaller 
// than anything that you may have in the table 
pos = ~pos; 
if (pos != data.Count && data[pos].Item1 <= item && data[pos].Item2 >= item) { 
    Console.WriteLine("Found: '{0}'", data[pos].Item3); 
} else { 
    Console.WriteLine("Not found"); 
} 

입니다 TupleComparer 클래스 :

class TupleComparer : IComparer<Tuple<long,long,string>> { 
    public int Compare(Tuple<long,long,string> x, Tuple<long,long,string> y) { 
     var res = x.Item1.CompareTo(y.Item1); 
     if (res != 0) return res; 
     res = x.Item2.CompareTo(y.Item2); 
     return (res != 0) ? res : String.CompareOrdinal(x.Item3, y.Item3); 
    } 
}