Совершенный идиоматический способ объединения двух символов, отсутствующих в списке, в строку - PullRequest
0 голосов
/ 01 февраля 2019

Я сделал большую часть своей разработки на C # и только изучаю F #.Вот что я хочу сделать в C #:

string AddChars(char char1, char char2) => char1.ToString() + char2.ToString();

EDIT: добавлен метод ToString() в пример C #.

Я хочу написать тот же метод в F #, и я незнаете, как это сделать:

let addChars char1 char2 = Char.ToString(char1) + Char.ToString(char2)

Есть ли способ добавить объединение этих char s в string без преобразования обоих в string сначала?


Sidenote:

Я также рассмотрел вопрос о создании массива char и преобразовании его в string, но это выглядит также расточительно.

let addChars (char1:char) (char2: char) = string([|char1; char2|])

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Ответ @ Abion47 уже перечисляет все возможные разумные методы, которые я могу придумать.Если вы заинтересованы в производительности, то вы можете провести быстрый эксперимент, используя функцию F # Interactive #time:

#time 
open System
open System.Text

let a = 'a'
let b = 'b'

Если сравнить три метода, то один с String [| a; b |] окажется в два разабыстро, как методы с участием ToString.На практике это, вероятно, не имеет большого значения, если вы не выполняете миллионы таких операций (как делает мой эксперимент), но это интересный факт:

// 432ms, 468ms, 472ms
for i in 0 .. 10000000 do
  let s = a.ToString() + b.ToString()
  ignore s

// 396ms 440ms, 458ms
for i in 0 .. 10000000 do
  let s = Char.ToString(a) + Char.ToString(b)
  ignore s

// 201ms, 171ms, 170ms
for i in 0 .. 10000000 do
  let s = String [| a;b |]
  ignore s
0 голосов
/ 01 февраля 2019

Как я уже сказал в своем комментарии, ваш код C # не будет делать то, что вы хотите (т.е. объединять символы в строку).В C # добавление char и char приведет к int.Причина этого заключается в том, что тип char не определяет оператор +, поэтому C # возвращается к ближайшему совместимому типу, который имеет значение, которое просто оказывается int.( Источник )

Итак, чтобы выполнить это поведение, вам нужно будет сделать нечто похожее на то, что вы уже пытаетесь сделать в F #:

char a = 'a';
char b = 'b';

// This is the wrong way to concatenate chars, because the
// chars will be treated as ints and the result will be 195.
Console.WriteLine(a + b);                              

// These are the correct ways to concatenate characters into
// a single string. The result of all of these will be "ab".
// The third way is the recommended way as it is concise and 
// involves creating the fewest temporary objects.
Console.WriteLine(a.ToString() + b.ToString());        
Console.WriteLine(Char.ToString(a) + Char.ToString(b));
Console.WriteLine(new String(new[] { a, b }));

(См. https://dotnetfiddle.net/aEh1FI)

F # аналогичен тому, что объединение двух или более char s не приводит к String. В отличие от C #, вместо этого получается другой char, нопроцесс тот же - значения char обрабатываются как int и складываются вместе, и в результате получается char представление суммы.

Так что на самом деле способ объединения chars в String в F # - это то, что у вас уже есть, и является прямым переводом эквивалента C #:

let a = 'a'
let b = 'b'

// This is still the wrong way (prints 'Ã')
printfn "%O" (a + b)

// These are still the right ways (prints "ab")
printfn "%O" (a.ToString() + b.ToString())
printfn "%O" (Char.ToString(a) + Char.ToString(b))
printfn "%O" (String [| a;b |]) // This is still the best way

(см. https://dotnetfiddle.net/ALwI3V)

Причина, по которойПодход «строка из символьного массива» - это лучший способ, состоящий из двух частей. Во-первых, он наиболее краткий, поскольку вы можете видеть, что этот подход предлагает самую короткую строку кода на обоих языках (и разница увеличивается только по мере добавленияи более char с). И во-вторых, только один временный объектсозданный (массив) перед финальным String, тогда как два других метода включают создание двух отдельных временных String объектов для подачи в конечный результат.

(Кроме того, я не уверен, работает ли он таким образом, поскольку конструкторы String скрыты во внешних источниках, но я представляю, что массив, переданный в конструктор, будет использоваться как *Данные поддержки 1042 *, поэтому они не будут потрачены впустую.) String являются неизменными, но использование переданного массива напрямую, поскольку созданные данные поддержки String могут привести кСитуация, когда ссылка на массив может храниться в другом месте программы и поставить под угрозу неизменность String, поэтому это предположение не будет реализовано на практике.(Credit: @CaringDev)


Еще один вариант, который вы можете сделать в F #, который может быть более идиоматическим, - это использовать функцию sprintf для объединения двух символов (Credit: @rmunn):

let a = 'a'
let b = 'b'
let s = sprintf "%c%c" a b

printfn "%O" s 

// Prints "ab"

(См. https://dotnetfiddle.net/Pp9Tee)

Тем не менее, предупреждение об этом методе заключается в том, что он почти наверняка будет намного медленнее, чем любой из трех других методов, перечисленных выше.Это потому, что вместо обработки массива или String данных напрямую, sprintf будет выполнять более продвинутую логику форматирования для вывода. (Я не в состоянии, где я мог бы в данный момент тестировать это сам, но подключенв приведенный ниже код @ TomasPetricek для бенчмаркинга, я не удивлюсь, если вы достигнете производительности в 10 раз или более.Конечный пользователь может заметить, но будьте осторожны, если это будет использоваться в любом критичном для производительности коде.

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