2015-02-18 4 views
0

У меня есть код ниже F #, который работает, чтобы объединить 4 строки, разделяя пробел, включая только те, которые не являются ни пустыми, ни пустыми ,F # как присоединиться к массиву строк только тогда, когда они не являются пустыми или пустыми

let street = 
    split.[5..8] 
    |> Array.filter (String.IsNullOrWhiteSpace >> not) 
    |> String.concat " " 

Это работает очень хорошо, но менее результативно, чем приведенная ниже реализация C#.

var street = ""; 
if (!string.IsNullOrWhiteSpace(items[5])) 
    street += items[5]; 
if (!string.IsNullOrWhiteSpace(items[6])) 
    street += string.IsNullOrWhiteSpace(street) ? items[6] : " " + items[6]; 
if (!string.IsNullOrWhiteSpace(items[7])) 
    street += string.IsNullOrWhiteSpace(street) ? items[7] : " " + items[7]; 
if (!string.IsNullOrWhiteSpace(items[8])) 
    street += string.IsNullOrWhiteSpace(street) ? items[8] : " " + items[8]; 
return street; 

Есть ли способ, которым я могу достичь того же стиля реализации в F #, вместо использования встроенных функций?

+2

Если вы ищете возможность использования, используйте StringBuilder. – Gustavo

+0

еще раз спасибо @Gustavo - поставит мою реализацию как ответ - не стесняйтесь редактировать :) – JamieS

ответ

1

Благодаря @Gustavo за предположение StringBuilder :)

let otherStreet = 
    let sb = new StringBuilder() 
     for i = 5 to 8 do 
      if not (String.IsNullOrWhiteSpace split.[i]) then 
       if sb.Length = 0 then 
        sb.Append split.[i] |> ignore 
       else 
        sb.Append " " |> ignore 
        sb.Append split.[i] |> ignore 
    sb.ToString() 
+0

Это действительно исправить проблему с производительностью? И как он сравнивается с реализацией C# на основе StringBuilder? Мы все исходим из того, что ограничение производительности происходит в самом конкатенации строк, но это предположение может быть не совсем правильным. – phoog

+0

с единственным изменением является в конкатенации, соответствующие тайминги для 1 млн записей были: - с помощью Sprintf - 3456ms - с помощью String.Format - 2989ms - с помощью StringBuilder - 2614ms C# реализация, использование StringBuilder принимает 2655ms – JamieS

4

Вот вариант, который удаляет явную итерацию и индексацию и может быть изменен, чтобы работать для любой коллекции, которая является SEQ пропускания в последовательности, а чем прямое разделение.

let otherStreet = 
    let combine (sb:StringBuilder) (s:String) = 
    if sb.Length = 0 then 
     sb.Append s 
    else 
     (sb.Append " ").Append s 

    split.[5..8] 
    |> Seq.filter (String.IsNullOrWhiteSpace >> not) 
    |> Seq.fold combine (StringBuilder()) 
    |> (fun sb -> sb.ToString()) 

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

+0

У меня была довольно слабая производительность от встроенных функций Seq, я обнаружил, что в то время как для ... внутри и для ... циклов производительность дает лучшую производительность. Не так приятно читать, но хорошо. – JamieS

+0

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

+0

Спасибо @Wayne - ради производительности, я собираюсь придерживаться решения, которое я придумал, но ценю помощь – JamieS

0

Если вы хотите, чтобы пройти через массив только один раз, то этот подход может работать для вас:

let street = Array.fold (fun x y -> if white y then x elif x="" then x+y else x+" "+y) "" 
street (split.[5..8]) 

, где «белый» означает «String.IsNullOrWhiteSpace».

+0

, даже заменяя «белый» на «String.IsNullOrWhiteSpace», это не компилируется? – JamieS

+0

Я предполагаю, что ваш 'String.IsNullOrWhiteSpace' имеет строку подписи -> boole. Он работает, например, 'let white s = s = "" || s = ""' –

Смежные вопросы