Получение каждого n-го элемента последовательности - PullRequest
7 голосов
/ 13 января 2011

Я ищу способ создать последовательность, состоящую из каждого n-го элемента другой последовательности, но, похоже, не нашел способа сделать это элегантным способом.Я, конечно, могу что-то взломать, но мне интересно, есть ли библиотечная функция, которую я не вижу.

Функции последовательности, имена которых оканчиваются на -i, кажутся вполне подходящими для выяснения, когдаэлемент - это n-й или (кратный n) -й элемент, но я вижу только iteri и mapi, ни один из которых на самом деле не подходит для задачи.

Пример:

let someseq = [1;2;3;4;5;6]
let partial = Seq.magicfunction 3 someseq

Тогда partial должно быть [3;6].Есть ли что-нибудь подобное?

Редактировать:

Если я не настолько амбициозен и допускаю, чтобы n был постоянным / известным, тогда ятолько что обнаружил, что должно работать следующее:

let rec thirds lst =
    match lst with
    | _::_::x::t -> x::thirds t // corrected after Tomas' comment
    | _ -> []

Есть ли способ написать это короче?

Ответы [ 2 ]

9 голосов
/ 13 января 2011

Seq.choose хорошо работает в этих ситуациях, потому что позволяет вам filter работать в mapi лямбде.

let everyNth n elements =
    elements
    |> Seq.mapi (fun i e -> if i % n = n - 1 then Some(e) else None)
    |> Seq.choose id

Аналогично здесь .

8 голосов
/ 13 января 2011

Вы можете получить поведение, составив mapi с другими функциями:

let everyNth n seq = 
  seq |> Seq.mapi (fun i el -> el, i)              // Add index to element
      |> Seq.filter (fun (el, i) -> i % n = n - 1) // Take every nth element
      |> Seq.map fst                               // Drop index from the result

Решение, использующее опции и choose, как предложено Анноном, будет использовать только две функции, но тело первойодин будет немного сложнее (но принцип по сути тот же).

Более эффективную версию, использующую непосредственно объект IEnumerator, написать не так сложно:

let everyNth n (input:seq<_>) = 
  seq { use en = input.GetEnumerator()
        // Call MoveNext at most 'n' times (or return false earlier)
        let rec nextN n = 
          if n = 0 then true
          else en.MoveNext() && (nextN (n - 1)) 
        // While we can move n elements forward...
        while nextN n do
          // Retrun each nth element
          yield en.Current }

РЕДАКТИРОВАТЬ: фрагмент также доступен здесь: http://fssnip.net/1R

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...