FP - Конденсат и «хороший» код - PullRequest
1 голос
/ 07 мая 2011

Написание кода на F # в большинстве случаев приводит к очень сжатой интуитивной работе. Этот кусок кода кажется мне крайне необходимым и неудобным.

  • times - массив значений с плавающей запятой

Строки внутри файла times.csv всегда выглядят так:

Mai 06 2011 05:43:45 nachm.,00:22.99
Mai 04 2011 08:59:12 nachm.,00:22.73
Mai 04 2011 08:58:27 nachm.,00:19.38
Mai 04 2011 08:57:54 nachm.,00:18.00
  • average генерирует среднее значение, отбрасывая самое низкое и самое высокое время
  • getAllSubsetsOfLengthN создает последовательность всех последовательных подмножеств длины n. Есть ли более приятное решение для этого? Или уже есть что-то подобное внутри ядра F #?
  • bestAverageOfN находит наименьшее среднее из всех подмножеств

let times =
    File.ReadAllLines "times.csv"
    |> Array.map (fun l -> float (l.Substring((l.LastIndexOf ':') + 1)))
let average set =
    (Array.sum set - Array.min set - Array.max set) / float (set.Length - 2)
let getAllSubsetsOfLengthN n (set:float list) =
    seq { for i in [0 .. set.Length - n] -> set
                                            |> Seq.skip i
                                            |> Seq.take n }
let bestAverageOfN n =
    times
    |> Array.toList
    |> getAllSubsetsOfLengthN n
    |> Seq.map (fun t -> t
                         |> Seq.toArray
                         |> average)
    |> Seq.min

То, что я ищу, - это более хорошие, короткие или более простые решения. Разумеется, за каждый полезный пост будет проголосовано:)

Ответы [ 4 ]

4 голосов
/ 07 мая 2011

Полагаю, getAllSubsetsOfLengthN можно заменить на Seq.windowed

, поэтому bestAverageOfN будет выглядеть так:

let bestAverageOfN n =
    times
    |> Seq.windowed n
    |> Seq.map average
    |> Seq.min
3 голосов
/ 07 мая 2011

Не задумываясь, есть несколько основных функциональных рефакторингов, которые вы можете сделать. Например, при расчете bestAverageOfN вы можете использовать состав функции:

let bestAverageOfN n =
    times
    |> Array.toList
    |> getAllSubsetsOfLengthN n
    |> Seq.map (Seq.toArray >> average)
    |> Seq.min

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

Просто ради общности, я бы, вероятно, сделал times аргументом bestAverageOfN:

let bestAverageOfN n times =
    times
    |> Seq.windowed n
    |> Seq.map (fun set ->
           (Array.sum set - Array.min set - Array.max set) / float (set.Length - 2))
    |> Seq.min
2 голосов
/ 07 мая 2011

Поскольку вы упомянули регулярное выражение для разбора ваших входных данных, я подумал, что покажу вам такое решение.Это может быть излишним, но это также более функциональное решение, так как регулярные выражения являются декларативными, в то время как подстрока более обязательна.Регулярное выражение также хорошо, так как его легче вырастить, если структура вашего ввода изменится, содержимое подстрок индекса может запутаться, и я постараюсь полностью этого избежать.*

Принятие реализации times @ ildjarn:

let times =
    File.ReadAllLines "times.csv"
    |> Array.map (function Groups @",.*?:(.*)$" [Float(value)] -> value)
1 голос
/ 07 мая 2011

Поскольку bestAversageOfN уже охвачено, вот альтернативная реализация times:

let times =
    File.ReadAllLines "times.csv"
    |> Array.map (fun l -> l.LastIndexOf ':' |> (+) 1 |> l.Substring |> float)
...