Я хотел бы написать функцию, которая фильтрует последовательность с использованием предиката, но в результате должен также ВКЛЮЧАТЬ первый элемент, для которого предикат возвращает false.
Логика была бы такой, если бы было ключевое слово break в F #
let myFilter predicate s =
seq {
for item in s do
yield item
if predicate item then
break
}
Я попробовал комбинации Seq.takeWhile и Seq.skipWhile, что-то вроде этого:
Seq.append
(Seq.takeWhile predicate s)
(Seq.skipWhile predicate s |> Seq.take 1)
... но проблема в том, что первый элемент, который соответствует предикату, теряется между takeWhile и skipWhile
Также обратите внимание, что входная последовательность является ленивой, поэтому любое решение, которое потребляет последовательность и принимает решения после этого, не является жизнеспособным.
Любые идеи?
Спасибо!
РЕДАКТОР: Спасибо ЛОТ за все ответы! Я не ожидал стольких ответов так быстро. Я скоро посмотрю на каждого из них. Теперь я просто хочу дать немного больше контекста. Рассмотрим следующую кодирующую ката, которая реализует оболочку:
let cmdProcessor state = function
| "q" -> "Good bye!"
| "h" -> "Help content"
| c -> sprintf "Bad command: '%s'" c
let processUntilQuit =
Seq.takeWhile (fun cmd -> cmd <> "q")
let processor =
processUntilQuit
>> Seq.scan cmdProcessor "Welcome!"
module io =
let consoleLines = seq { while true do yield System.Console.ReadLine () }
let display : string seq -> unit = Seq.iter <| printfn "%s"
io.consoleLines |> processor|> io.display
printf "Press any key to continue..."
System.Console.ReadKey ()|> ignore
У этой реализации есть проблема, что она не печатает "До свидания!" когда введена команда q.
Что я хочу сделать, это реализовать функцию processUntilQuit, чтобы она обрабатывала все команды до тех пор, пока "q", включая "q".