2010-11-03 9 views
3

Могу ли я сделать это, не перебирая весь список?найти все строки в списке, содержащем x или y?

List<string> responseLines = new List<string>(); 

список заполняется примерно 300 строками текста.

следующее Я хочу найти список и создать второй список всех строк, начинающихся с «abc» или содержащих «xyz».

Я знаю, что могу сделать для каждого, но есть ли лучший способ?

+2

Linq является удивительным для этого материала :) –

+1

Если вы сохраните свой список отсортированным, вы можете найти все строки, начинающиеся с «abc», без необходимости перебирать их все, но вы не можете найти те, которые содержат " xyz ", не глядя на каждого. – Gabe

ответ

7

Вы можете использовать LINQ. Это ничем не отличается производительность разумно используя foreach - это довольно много, что она делает за кулисами, - но вы можете предпочесть синтаксис:

var query = responseLines.Where(s => s.StartsWith("abc") || s.Contains("xyz")) 
         .ToList(); 

(Если вы счастливы дело с IEnumerable<string>, а не List<string> то вы можете пропустить окончательный ToList вызов)

+1

Обратите внимание, что это все еще проходит по всему списку, вам просто не нужно было писать 'foreach' самостоятельно. – Gabe

+0

FYI - «Содержит» должно быть «xyz» – Phil

+0

Это итерация по каждому символу в каждой строке. – Svisstack

3

Использование LINQ:.

List<string> list = responseLines.Where(x => x.StartsWith("abc") || x.Contains("xyz")).ToList(); 
+0

Это итерация по каждому символу в каждой строке. – Svisstack

+3

+1 для противодействия Svisstack. – Inisheer

4
var newList = (from line in responseLines 
       where line.StartsWith("abc") || line.Contains("xyz") 
       select line).ToList(); 
+0

Это итерация по каждому символу в каждой строке. – Svisstack

+0

Любопытно о дате голосования. – Inisheer

+3

@Svisstack: мы слышали вас; вам не нужно завышать каждый ответ и повторять сам. Кроме того, вы ошибаетесь в своем downvoting: ответы правильно решают вопрос, поэтому ни одна из них не указана в соответствии с часто задаваемыми вопросами. – CesarGon

4

Попробуйте это:

List<string> responseLines = new List<string>(); 
List<string> myLines = responseLines.Where(line => line.StartsWith("abc", StringComparison.InvariantCultureIgnoreCase) || line.Contains("xyz")).ToList(); 

StartsWith и Contains ярлык - Contains будет оценивать только если StartsWith не выполняется. Это все равно повторяет весь список, но, конечно, нет способа избежать этого, если вы хотите проверить весь список, но он сэкономит вам от , делая , набрав foreach.

+0

Это итерация по каждому символу в каждой строке. – Svisstack

+4

+1 для противодействия Svisstack. – Inisheer

+0

@Svisstack - трудно избежать того, что при выполнении Содержит лучшее, что вы можете сделать, это избегать Содержит, если нет необходимости в этой строке из-за другого условия, которое выполняется первым. По крайней мере, мы позволяем любым интеллектуальным комбинациям, встроенным в LINQ, выполнять итерацию символов. Я не вижу, чтобы вы предлагали решение, которое позволяет избежать этого? – slugster

1

LINQ работает хорошо, предлагая вам улучшенный синтаксис для такого рода вещей (см. Ответ LukeH на хороший пример), но он не быстрее, чем повторяет его вручную.

Если вам нужно часто выполнять эту операцию, вам может потребоваться какая-то индексированная структура данных, которая следит за всеми строками «abc» или «xyz», когда они входят в список, и поэтому может использовать более быстрый алгоритм для их обслуживания по запросу, а не повторение всего списка.

Если вам не нужно делать это часто, это, вероятно, «преждевременная оптимизация».

2

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

Это зависит от того, как загружен файл List - этот код не отображается. Это было бы эффективно, если бы вы читали из текстового файла, так как тогда вы могли бы просто использовать свой запрос LINQ для прямого использования входных данных с использованием File.ReadLines в качестве источника вместо окончательного List<string>.

var query = File.ReadLines("input.txt"). 
     Where(s => s.StartsWith("abc") || s.Contains("xyz")) 
     .ToList(); 
1

Проще говоря, нет никакой возможности алгоритм, который может гарантировать, что вы никогда не придется перебирать каждый элемент в списке. Тем не менее, можно улучшить количество элементов, необходимых для повторного использования - сортировка списка, прежде чем вы начнете поиск.Таким образом, единственное, что вам нужно было бы повторить по всему списку, было бы тогда, когда оно будет заполнено только «abc» и «xyz».

Предполагая, что вам не обязательно иметь предварительно отсортированный список к моменту поиска по нему, то единственным способом повысить скорость поиска будет использование другой структуры данных, чем список - например, binary search tree.

Смежные вопросы