2015-07-25 5 views
4

Предположим, что у меня есть длинная строка и хотел бы получить перечислитель (для LINQ goodness), который начинается в середине строки при заданном индексе. То естьGetEnumerator() в середине строки

var longString = GetLongString(); 
var index = 99999; 

// seems unnecessarily expensive to allocate a new string 
var enumerator = longString.Substring(9999).GetEnumerator(); 

// Use LINQ. 
enumerator.TakeWhile(/* ... */); 

есть ли способ (то есть: дешевле/быстрее) сделать это?

+0

я до сих пор интересно, какую пользу что-то подобное будет иметь более, скажем, Substring – moarboilerplate

ответ

9

Рассмотрим Enumerable.Skip:

longString.Skip(9999).TakeWhile(/* ... */); 

Однако, имейте в виду, что, как Michael Liu писал Skip работы в итерационном пути (строго говоря, это зависит от реализации, но, по крайней мере, это то, что вы обычно смотрите, например .NET Framework 4.6 Reference Sources). Если он вызывает измеримый медлительность в вашем случае, посмотрите на метод расширения Майкла.


  1. D.Knuth: "преждевременная оптимизация есть корень всех зол"
+1

Это правильный способ сделать это. Будет использовать его как по существу массив символов без перераспределения новой строки. – Tim

+0

@Tim Это действительно типичный способ игнорировать элементы, использующие Linq, но in может принимать 'O (N)' вместо 'O (1)' time. – AlexD

5

Использование longString.Skip(n), как в AlexD's answer, составит п вызовы метода MoveNext Базового счетчику, чтобы пропустить мимо всех персонажей, которых вы не заботитесь. При больших значениях п, можно повысить производительность, написав метод пользовательского итератора:

public static IEnumerable<char> EnumerableSubstring(this string s, int startIndex) 
{ 
    for (; startIndex < s.Length; startIndex++) 
     yield return s[startIndex]; 
} 

Пример использования:

longString.EnumerableSubstring(9999).TakeWhile(/* ... */)