F#, char seq -> строки
быстрый вопрос, который может быть больше напыщенным (но я надеюсь быть просветленным вместо этого).
в F# строка совместима с Seq таким образом, что" abcd " | > Seq.отображение F будет работать на строке.
это блестящее средство для работы со строками, например, чтобы взять первые 5 символов из строки:
"abcdef01234567" |> Seq.take 5
или удаление повторяющихся символов:
"abcdeeeeeee" |> Seq.distinct
проблема в том, что как только у вас есть результат char seq, он становится чрезвычайно неудобно снова преобразовывать это в строку, строку.concat "" требует, чтобы члены были строками, поэтому я в конечном итоге делаю это много:
"abcdef01234567"
|> Seq.take 5
|> Seq.map string
|> String.concat ""
настолько, что у меня есть функция, которую я использую в 90% моих проектов:
let toString : char seq -> string = Seq.map string >> String.concat ""
Я чувствую, что это над вершиной, но везде, где я ищу альтернативу, я встречаюсь с отвратительными вещами, такими как StringBuilder или inlining лямбда и использование нового:
"abcdef01234567"
|> Seq.take 5
|> Seq.toArray
|> fun cs -> new string (cs) (* note you cannot just |> string *)
мое (возможно, сумасшедшее) ожидание, которое я хотел бы видеть в язык заключается в том, что когда Seq используется в string, сигнатура типа из результирующего выражения должна быть string -> string. То есть, что входит, то и выходит. "abcd" / > Seq.возьмите 3 = "abc".
есть ли причина, по которой мои ожидания от высокоуровневой манипуляции строками ошибочны в этом случае?
есть ли у кого-нибудь рекомендация подойти к этому в хорошей манере, Я чувствую, что должен что-то упустить.
4 ответов
Я только что исследовал это сам. Я нашел эту систему.Строка.Конкат работает довольно хорошо, например
"abcdef01234567" |> Seq.take 5 |> String.Concat;;
предположим, что вы открыли System
.
функции Seq
модуль интернет только с последовательностями, т. е. когда вы звоните им с string
, они только "видят" a Seq<char>
и работайте на нем соответственно. Даже если они сделали специальную проверку, чтобы увидеть, был ли аргумент string
и предпринял некоторые специальные действия (например, оптимизированную версию функции только для строк), они все равно должны были бы вернуть ее как Seq<char>
чтобы успокоить систему типов F# - в этом случае вам нужно будет проверить возвращаемое значение везде, чтобы увидеть, было ли это на самом деле string
.
хорошей новостью является то, что F# имеет встроенные ярлыки для некоторых из кода, который вы пишете. Например:
"abcdef01234567" |> Seq.take 5
можно сократить до:
"abcdef01234567".[..4] // Returns the first _5_ characters (indices 0-4).
некоторые из других вам все равно придется использовать Seq
Хотя, или напишите свою собственную оптимизированную реализацию для работы со строками.
вот функция для получения отдельных символов в строке:
open System.Collections.Generic
let distinctChars str =
let chars = HashSet ()
let len = String.length str
for i = 0 to len - 1 do
chars.Add str.[i] |> ignore
chars
F# имеет модуль строки и Seq
функциональность модуля специализированная для строк.
F# получил возможность использовать конструкторы в качестве функций, так как этот вопрос был задан 5 лет назад. Я бы использовал Строки(Char[]) для преобразования символов в строку. Вы можете конвертировать в и из последовательности F# или списка F#, но я бы, вероятно, просто использовал модуль массива F#, используя строку.ToCharArray метод слишком.
printfn "%s" ("abcdef01234567".ToCharArray() |> Array.take 5 |> String)
Если вы действительно хотели использовать char seq
затем вы можете передать его в строку следующим образом:
printfn "%s" ("abcdef01234567" |> Seq.take 5 |> Array.ofSeq |> String)