Подтвердить что ты не робот

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

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

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

Вывод:

Случай 1:

myString: C:\Files\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: True

Случай 2:

myString: C:\Files3\myfile.doc
listOfString: C:\Files\, C:\Files2\
Result: False

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

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

4b9b3361

Ответ 1

С LINQ и с использованием С# (в наши дни я не знаю VB):

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

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

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

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


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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

Мне понравился ответ Marc, но мне нужно, чтобы Contains соответствовал CaSe InSenSiTiVe.

Это было решение:

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

Ответ 5

На основе ваших шаблонов одним из улучшений было бы изменение на использование 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 на ContainsKey, и поиск будет O (1) вместо O (N). Вы должны убедиться, что пути точно совпадают. Обратите внимание, что это не общее решение, как @Marc Gravell, но оно соответствует вашим примерам.

Извините за пример С#. У меня не было достаточно кофе, чтобы перевести на VB.

Ответ 6

Я не уверен, что это более эффективно, но вы могли бы подумать об использовании Lambda Expressions.

Ответ 7

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

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

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

Ответ 8

Вместо списка строк вы могли бы использовать регулярные выражения? Даже если вам приходилось использовать несколько регулярных выражений, я бы подумал, что тестирование пары (сотни?) Было бы лучше, чем тысячи сравнений строк.

Ответ 9

Если скорость критическая, вам может понадобиться искать алгоритм Aho-Corasick для наборов шаблонов.

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

Ответ 10

myList.Any(myString.Contains);

Ответ 11

Недостаток метода Contains заключается в том, что он не позволяет указать тип сравнения, который часто важен при сравнении строк. Он всегда чувствителен к культуре и регистру. Поэтому я думаю, что ответ WhoIsRich является ценным, я просто хочу показать более простую альтернативу:

listOfStrings.Any(s => s.Equals(myString, StringComparison.OrdinalIgnoreCase))

Ответ 12

Старый вопрос Но так как VB.NET был первоначальным требованием. Используя те же значения принятого ответа:

listOfStrings.Any(Function(s) myString.Contains(s))