Высокоскоростное сопоставление строк в C #

У меня есть список из примерно 10 000 сотрудников в List , и у меня есть ListBox , который содержит подмножество этих персонал, в зависимости от поискового запроса в текстовом поле.

Допустим, объект Staff имеет следующие публично доступные свойства:

string FirstName
string LastName
string MiddleName
   int StaffID
   int CostCentre

Я мог бы написать такую ​​функцию:

bool staffMatchesSearch(Staff stf)
{
  if (tbSrch.Text.Trim() == string.Empty)
    return true; // No search = match always.

  string s = tbSrch.Text.Trim().ToLower();

  // Do the checks in the order most likely to return soonest:
  if (stf.LastName.ToLower().Contains(s))
    return true;
  if (stf.FirstName.ToLower().Contains(s))
    return true;
  if (stf.MiddleName.ToLower().Contains(s))
    return true;

  if (stf.CostCentre.ToString().Contains(s))
    return true; // Yes, we want partial matches on CostCentre
  if (stf.StaffID.ToString().Contains(s))
    return true; // And also on StaffID

  return false;
}

, а затем сделать что-то вроде:

tbSrch_TextChanged(object sender, EventArgs e)
{
  lbStaff.BeginUpdate();
  lbStaff.Items.Clear();

  foreach (Staff stf in staff)
    if (staffMatchesSearch(stf))
      lbStaff.Items.Add(stf);

  lbStaff.EndUpdate();
}

Фильтрация пересматривается каждые когда пользователь изменяет содержимое поля tbSrch .

Это работает, и это не ужасно медленно, но мне было интересно, смогу ли я сделать это быстрее?

Я попытался переписать все, чтобы оно было многопоточным, однако при наличии всего лишь 10 000 сотрудников накладные расходы, казалось, сводили на нет большую часть выгоды. Кроме того, было множество других ошибок, например, если при поиске по запросу «Джон» пользователь сначала нажимает «J», потоки накапливаются, но когда пользователь нажимает «o», другой набор помещается в буфер до того, как первая партия будет иметь шанс вернуть свои результаты. Часто результаты возвращаются в беспорядочном порядке, и происходят всевозможные неприятности.

Я могу придумать несколько хитростей, которые значительно улучшили бы лучший сценарий, но они также сделали бы худший сценарий намного хуже.

Есть ли у вас какие-нибудь идеи, как это можно улучшить?


Отличные предложения, которые я уже реализовал, и их результаты:

  • Добавьте задержку для события ValueChanged , чтобы, если Пользователь быстро набирает на клавиатуре 5-значное имя, он выполняет только 1 поиск в конце, а не 5 подряд.
  • Предварительно оценить ToLower () и сохранить в классе Staff (как атрибут [NonSerialized] , чтобы он не занимал лишнего места в файл сохранения).
  • Добавьте свойство get в Staff , которое возвращает все критерии поиска как одну длинную объединенную строку в нижнем регистре. Затем запустите для этого один Contains () . (Эта строка хранится в объекте Staff , поэтому она создается только один раз.)

Пока что они снизили время поиска с примерно 140 мс до примерно 60 мс (хотя эти числа очень субъективны в зависимости от фактический выполненный поиск и количество возвращенных результатов).

13
задан Ozzah 16 November 2011 в 05:34
поделиться