Просто для полноты, вот версия, которая делает то же самое напрямую, используя функцию fold
. Это можно сделать довольно элегантно, потому что методы StringBuilder
возвращают StringBuilder
(что позволяет вам связывать их в C #). Это также можно использовать для складывания.
Предположим, у нас есть список кортежей из решения Маурисио:
let properties =
[ (oldUser.FirstName, newUser.FirstName, "first_name")
(oldUser.LastName, newUser.LastName, "last_name")
(oldUser.UserName, newUser.UserName, "username") ]
Теперь вы можете написать следующий код (он также возвращает флаг, если что-то изменилось):
let init = false, new StringBuilder()
let anyChange, formatted =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, newVal, name) ->
if (oldVal = newVal) anyChange, sb
else true, sb.AppendFormat("{0} = '{1}'", name, newVal)) init
Состояние, сохраняемое при свертывании, имеет тип bool * StringBuilder
, и мы начнем с начального значения, содержащего пустой строитель строк и false. На каждом шаге мы либо возвращаем исходное состояние (если значение совпадает с предыдущим), либо новое состояние, содержащее true
и новую версию StringBuilder
, возвращаемую AppendFormat
.
Использование рекурсии в явном виде также будет работать, но когда вы можете использовать некоторую встроенную функцию F #, обычно такой подход проще использовать. Если вам нужно обрабатывать вложенные сущности каждой сущности, вы можете использовать функцию Seq.collect
вместе с рекурсией, чтобы получить список свойств, которые вам нужно обработать, используя fold
. Псевдокод может выглядеть так:
let rec processEntities list names =
// Pair matching entity with the name from the list of names
List.zip list names
|> List.collect (fun (entity, name) ->
// Current element containing old value, new value and property name
let current = (entity.OldValue, entity.NewValue, name)
// Recursively proces nested entitites
let nested = processEntities entity.Nested
current::nested)
Это может быть более элегантно написано с использованием выражений последовательности:
let rec processEntities list =
seq { for entity, name in List.zip list names do
yield (entity.OldValue, entity.NewValue, name)
yield! processEntities entity.Nested }
Тогда вы можете просто вызвать processEntities
, который возвращает плоский список сущностей и обработать сущности, используя fold
, как в первом случае.