Проверьте, содержит ли строка элемент из списка (строк)



для следующего блока кода:



For I = 0 To listOfStrings.Count - 1
If myString.Contains(lstOfStrings.Item(I)) Then
Return True
End If
Next
Return False


выход:



Пример 1:



myString: C:Filesmyfile.doc
listOfString: C:Files, C:Files2
Result: True


Пример 2:



myString: C:Files3myfile.doc
listOfString: C:Files, C:Files2
Result: False


список (listOfStrings) может содержать несколько элементов (минимум 20), и он должен быть проверен на тысячи строк (например, myString).



есть ли лучший (более эффективный) способ написать этот код?

519   9  

9 ответов:

С LINQ, и с помощью C# (я не знаю VB много в эти дни):

bool b = listOfStrings.Any(s=>myString.Contains(s));

или (короче и эффективнее, но, возможно, менее понятно):

bool b = listOfStrings.Any(myString.Contains);

если бы вы тестировали равенство, то стоило бы посмотреть на HashSet и т. д., Но это не поможет с частичными совпадениями, если вы не разделите его на фрагменты и не добавите порядок сложности.


update: если вы действительно имеете в виду" StartsWith", то вы можете отсортировать список и поместить его в массив ; затем использовать Array.BinarySearch чтобы найти каждый элемент-проверьте путем поиска, чтобы увидеть, если это полное или частичное совпадение.

было несколько предложений из более раннего аналогичного вопроса"лучший способ проверить существующую строку против большого списка сопоставимых".

регулярное выражение может быть достаточно для ваших требований. Выражение было бы конкатенацией всех подстрок-кандидатов, С или"|" оператором между ними. Конечно, вам придется следить за неэкранированные символы при построении выражения, или отказа скомпилировать его из-за сложности или ограничения по размеру.

другой способ сделать это было бы построить структура данных trie чтобы представить все подстроки-кандидаты (это может несколько дублировать то, что делает сопоставитель регулярных выражений). По мере прохождения каждого символа в тестовой строке вы создадите новый указатель на корень trie и переместите существующие указатели на соответствующий дочерний элемент (если таковой имеется). Вы получаете совпадение, когда любой указатель достигает листа.

когда вы строите свои строки, это должно быть так

bool inact = new string[] { "SUSPENDARE", "DIZOLVARE" }.Any(s=>stare.Contains(s));

Мне понравился ответ Марка, но мне нужно было, чтобы совпадение содержало регистр без учета регистра.

решение:

bool b = listOfStrings.Any(s => myString.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0))

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

кроме того, основываясь на ваших шаблонах, похоже, что вы можете извлечь первую часть пути для myString, а затем отменить сравнение - поиск начального пути myString в списке струны, а не наоборот.

string[] pathComponents = myString.Split( Path.DirectorySeparatorChar );
string startPath = pathComponents[0] + Path.DirectorySeparatorChar;

return listOfStrings.Contains( startPath );

EDIT: это было бы еще быстрее, используя идею HashSet @Marc Gravell упоминает, так как вы можете изменить Contains to ContainsKey и поиск будет O(1) вместо O (N). Вам придется убедиться, что пути совпадают. Обратите внимание, что это не общее решение, как у @Marc Gravell, но оно адаптировано к вашим примерам.

извините за пример C#. У меня не было достаточно кофе, чтобы переводить ВБ.

Я не уверен, что это более эффективно, но вы могли бы подумать об использовании at Лямбда-Выражения.

вы проверили скорость?

т. е. вы создали образец набора данных и профилированного это? Это может быть не так плохо, как ты думаешь.

Это также может быть то, что вы могли бы породить в отдельный поток и дать иллюзию скорости!

Если скорость имеет решающее значение, вы можете искать алгоритм АХО-Корасика для наборов моделей.

Это бор со ссылками отказа, то есть сложность равна O(n+m+k), где n-длина входного текста, m-суммарная длина шаблонов и k-количество совпадений. Вам просто нужно изменить алгоритм, чтобы завершить работу после того, как будет найдено первое совпадение.

myList.Any(myString.Contains);

Comments

    Ничего не найдено.