Выберите следующие N элементов IEnumerable <T> - PullRequest
4 голосов
/ 07 марта 2009

Скажем, у вас есть некоторый IEnumerable с именем S длины N. Я хотел бы выбрать все непрерывные подпоследовательности длины n <= N из S. </p>

Если бы S был, скажем, строкой, это было бы довольно легко. Есть (S.Length - n + 1) подпоследовательности длины n. Например, «abcdefg» - это длина (7), что означает, что он имеет (5) подстрок длины (3): «abc», «bcd», «cde», «def», «efg».

Но S может быть любым IEnumerable, поэтому этот маршрут не открыт. Как мне использовать методы расширения, чтобы решить эту проблему?

Ответы [ 6 ]

4 голосов
/ 07 марта 2009

F # имеет библиотечную функцию Seq.windowed для этого.

http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Collections.Seq.html

// windowed : int -> seq<'a> -> seq<array<'a>>
let windowed n (s: seq<_>) =    
    if n <= 0 then Helpers.invalid_arg2 "n" "the window size must be positive"
    { let arr = Array.zero_create n 
      let r = ref (n-1)
      let i = ref 0 
      use e = s.GetEnumerator() 
      while e.MoveNext() do 
          do arr.[!i] <- e.Current
          do i := (!i + 1) % n 
          if !r = 0 then 
              yield Array.init n (fun j -> arr.[(!i+j) % n])
          else 
              do r := (!r - 1) }
2 голосов
/ 07 марта 2009

На самом деле, вы можете использовать LINQ для решения этой проблемы, например,

var subList = list.Skip(x).Take(y);

где список IEnumerable

0 голосов
/ 05 октября 2016

Для будущих читателей.

Вот небольшой пример.

    private static void RunTakeSkipExample()
    {
        int takeSize = 10; /* set takeSize to 10 */

        /* create 25 exceptions, so 25 / 10 .. means 3 "takes" with sizes of 10, 10 and 5 */
        ICollection<ArithmeticException> allArithExceptions = new List<ArithmeticException>();
        for (int i = 1; i <= 25; i++)
        {
            allArithExceptions.Add(new ArithmeticException(Convert.ToString(i)));
        }

        int counter = 0;
        IEnumerable<ArithmeticException> currentTakeArithExceptions = allArithExceptions.Skip(0).Take(takeSize);
        while (currentTakeArithExceptions.Any())
        {
            Console.WriteLine("Taking!  TakeSize={0}. Counter={1}. Count={2}.", takeSize, (counter + 1), currentTakeArithExceptions.Count());

            foreach (ArithmeticException ae in currentTakeArithExceptions)
            {
                Console.WriteLine(ae.Message);
            }

            currentTakeArithExceptions = allArithExceptions.Skip(++counter * takeSize).Take(takeSize);
        }

    }

Выход:

Taking!  TakeSize=10. Counter=1. Count=10.
1
2
3
4
5
6
7
8
9
10
Taking!  TakeSize=10. Counter=2. Count=10.
11
12
13
14
15
16
17
18
19
20
Taking!  TakeSize=10. Counter=3. Count=5.
21
22
23
24
25

Вы можете видеть .Message для каждого исключения, чтобы убедиться, что каждое отдельное исключение было "принято".

А теперь цитата из фильма!

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

0 голосов
/ 02 сентября 2012

Вот новый метод расширения, чтобы делать то, что вы хотите в C #

static IEnumerable<IEnumerable<T>> Subseqs<T>(this IEnumerable<T> xs, int n) 
{
  var cnt = xs.Count() - n;  
  Enumerable.Range(0, cnt < 0 ? 0 : cnt).Select(i => xs.Skip(i).Take(n));
} 
0 голосов
/ 18 мая 2010
IEnumerable<IEnumerable<T>> ContiguousSubseqences<T>(this IEnumerable<T> seq, Func<T,bool> constraint)
{
    int i = 0;
    foreach (T t in seq)
    {
        if (constraint(t))
            yield return seq.Skip(i).TakeWhile(constraint);
        i++;
    }
}
0 голосов
/ 07 марта 2009

Вы можете использовать расширение Select, предоставляющее индекс, для создания объекта, содержащего индекс и значение, а затем разделить индекс на длину, чтобы разместить их в группы:

var x = values.Select((n, i) => new { Index = i, Value = n }).GroupBy(a => a.Index / 3);
...