먼저 ListControl
데이터 소스를 보는 방법을 변경 하고 결과 IEnumerable<string>
를 List<string>
. 특히 몇 개의 문자를 입력 한 경우 비효율적 일 수 있습니다 (필요하지 않음). 데이터의 광범위한 사본을 만들지 마십시오 .
.Where()
결과를 IList
(검색) 에서 필요한 것만 구현하는 컬렉션으로 래핑 합니다 . 이렇게하면 입력 된 각 문자에 대한 새로운 큰 목록을 만들 수 있습니다.
- 대안으로 LINQ를 피하고 더 구체적이고 최적화 된 것을 작성합니다. 목록을 메모리에 유지하고 일치하는 인덱스 배열을 만들고 배열을 재사용하여 각 검색에 대해 다시 할당 할 필요가 없습니다.
두 번째 단계는 작은 목록으로 충분할 때 큰 목록에서 검색하지 않는 것입니다. 사용자가 "ab"를 입력하기 시작하고 "c"를 추가하면 큰 목록에서 조사 할 필요가 없습니다. 필터링 된 목록에서 검색하면 충분합니다 (더 빠릅니다). 상세 검색매번 이 가능하며 매번 전체 검색을 수행하지 마십시오.
세 번째 단계는 더 어려울 수 있습니다 . 빠르게 검색 할 수 있도록 데이터를 정리하십시오 . 이제 데이터를 저장하는 데 사용하는 구조를 변경해야합니다. 다음과 같은 나무를 상상해보십시오.
알파벳
더 나은 Ceil 추가
뼈 윤곽 위
이것은 단순히 배열로 구현 될 수 있습니다 (ANSI 이름으로 작업하는 경우 그렇지 않으면 사전이 더 좋습니다). 다음과 같이 목록을 작성하십시오 (예시 목적으로 문자열의 시작과 일치 함).
var dictionary = new Dictionary<char, List<string>>();
foreach (var user in users)
{
char letter = user[0];
if (dictionary.Contains(letter))
dictionary[letter].Add(user);
else
{
var newList = new List<string>();
newList.Add(user);
dictionary.Add(letter, newList);
}
}
그러면 첫 번째 문자를 사용하여 검색이 수행됩니다.
char letter = textBox_search.Text[0];
if (dictionary.Contains(letter))
{
listBox_choices.DataSource =
new MyListWrapper(dictionary[letter].Where(x => x.Contains(textBox_search.Text)));
}
MyListWrapper()
첫 번째 단계에서 제안한대로 사용 했습니다 (하지만 간결성을 위해 두 번째 제안에서 생략했습니다. 사전 키에 맞는 크기를 선택하면 각 목록을 짧고 빠르게 유지하여 다른 것은 피할 수 있습니다). 또한 사전에 처음 두 문자를 사용하려고 할 수 있습니다 (목록이 많고 짧음). 이것을 확장하면 나무가 생깁니다 (하지만 그렇게 많은 수의 항목이 있다고 생각하지 않습니다).
문자열 검색을위한 다양한 알고리즘 이 있습니다 (관련 데이터 구조 포함).
- 유한 상태 오토 마톤 기반 검색 :이 접근 방식에서는 저장된 검색 문자열을 인식하는 결정 론적 유한 오토 마톤 (DFA)을 구성하여 역 추적을 방지합니다. 이들은 구성하는 데 비용이 많이 들지만 일반적으로 powerset 구성을 사용하여 생성되지만 사용이 매우 빠릅니다.
- 스텁 : Knuth–Morris–Pratt는 검색 할 문자열이있는 입력을 접미사로 인식하는 DFA를 계산합니다. Boyer–Moore는 바늘 끝부터 검색을 시작하므로 일반적으로 각 단계에서 전체 바늘 길이만큼 앞으로 이동할 수 있습니다. Baeza–Yates는 이전 j 문자가 검색 문자열의 접두사 였는지 여부를 추적하므로 퍼지 문자열 검색에 적용 할 수 있습니다. bitap 알고리즘은 Baeza–Yates의 접근 방식을 적용한 것입니다.
- 색인 방법 : 더 빠른 검색 알고리즘은 텍스트의 전처리를 기반으로합니다. 예를 들어 접미사 트리 또는 접미사 배열과 같은 하위 문자열 인덱스를 빌드 한 후 패턴 발생을 빠르게 찾을 수 있습니다.
- 기타 변형 : 트라이 그램 검색과 같은 일부 검색 방법은 "일치 / 불일치"보다는 검색 문자열과 텍스트 사이의 "가까움"점수를 찾기위한 것입니다. 이를 "퍼지"검색이라고도합니다.
병렬 검색에 대한 몇 마디. 가능하지만 병렬로 만들기위한 오버 헤드가 검색 자체보다 훨씬 높을 수 있기 때문에 사소한 일이 아닙니다. 검색 자체를 병렬로 수행하지는 않지만 (파티션 및 동기화가 곧 너무 확장되고 복잡해질 수 있음) 검색을 별도의 스레드로 이동합니다 . 주 스레드가 바쁘지 않으면 사용자가 입력하는 동안 지연을 느끼지 않을 것입니다 (200ms 후에 목록이 표시되는지 여부는 기록하지 않지만 입력 한 후 50ms를 기다려야하는 경우 불편 함을 느낄 것입니다) . 물론 검색 자체가 충분히 빨라야합니다.이 경우 검색 속도를 높이기 위해 스레드를 사용하지 않고 UI 응답 성 을 유지합니다 . 쿼리를 UI가 중단되지 않지만 쿼리가 느린 경우 별도의 스레드에서 여전히 느립니다 (또한 여러 개의 순차적 요청도 처리해야 함).
HashSet<T>
문자열 의 일부 를 검색하기 때문에 여기서는 도움이되지 않습니다 .