Я написал эту функцию, которая объединяет два списка вместе, но, поскольку я новичок в функциональном программировании, мне было интересно, есть ли лучший (более простой) способ сделать это?

let a = ["a"; "b"; "c"]
let b = ["d"; "b"; "a"]

let merge a b =
    // take all a and add b
    List.fold (fun acc elem -> 
                     let alreadyContains = acc |> List.exists (fun item -> item = elem)
                     if alreadyContains = true then
                        acc
                     else 
                        elem :: acc |> List.rev
                     ) b a                

let test = merge a b 

Ожидаемый результат: ["a"; «б»; «с»; «d»], я возвращаю список, чтобы сохранить исходный порядок. Я думал, что смогу добиться того же, используя List.foldBack (и отбросив List.rev), но это приводит к ошибке:

Несоответствие типов. Ожидая 'а
но учитывая 'список
Результирующий тип будет бесконечным при объединении "a" и "a list"

Почему есть разница при использовании foldBack?

f#
2
Jammes 23 Фев 2015 в 18:58

2 ответа

Лучший ответ

Если бы я хотел написать это так же, как ваша исходная версия (используя fold), то основное изменение, которое я бы сделал, - это переместить List.rev за пределы функции (вы вызываете List.rev каждый раз, когда вы добавляете новый элемент, что неверно, если вы добавляете четное количество элементов!)

Итак, решение, очень похожее на ваше, будет:

let merge a b =
  (b, a) 
  ||> List.fold (fun acc elem -> 
        let alreadyContains = acc |> List.exists (fun item -> item = elem)
        if alreadyContains = true then acc
        else elem :: acc)   
  |> List.rev

Здесь используется двухканальный оператор ||> для передачи двух параметров функции fold (в этом нет необходимости, но я считаю это немного лучше), а затем передает результат в List.rev.

3
Tomas Petricek 23 Фев 2015 в 16:16

Вы можете использовать что-то вроде следующего

let merge a b =
    a @ b
    |> Seq.distinct
    |> List.ofSeq

Обратите внимание, что это сохранит порядок и удалит все дубликаты.

В F # 4.0 это будет упрощено до

let merge a b = a @ b |> List.distinct
8
Patrick McDonald 23 Фев 2015 в 16:08