В F # определить функцию zip для двух списков - PullRequest
0 голосов
/ 08 марта 2020

Возникли проблемы с проблемой:

Определите функцию с именем zip, которая принимает пару (кортеж) списков одинаковой длины в качестве одного параметра и возвращает список пар. Первая пара должна содержать первый элемент каждого списка, вторая пара содержит второй элемент каждого списка и т. Д.

Я застрял и ищу совет, если я направляюсь в правильное направление или следует попробовать другой подход.

Это должно быть одно определение функции без вложенных функций и нельзя использовать встроенные функции!

Я сделал следующее:

    let rec zip (a , b) =
       if List.length a = 1 then List.head a , List.head b
       else zip (List.tail a , List.tail b) 

при вводе

     > zip (["a"; "b"; "c"; "d"; "e"], [1; 2; 3; 4; 5]);;

      val it : string * int = ("e", 5) 

возвращается. Ожидаемый результат должен быть

     val it : (string * int) list = [("a", 1); ("b", 2); ("c", 3); ("d", 4); ("e", 5)]

Ответы [ 2 ]

3 голосов
/ 09 марта 2020

Давайте начнем с вашей первоначальной реализации:

let rec zip (a , b) =
    if List.length a = 1 then List.head a , List.head b
    else zip (List.tail a , List.tail b) 

Прежде всего, тип неправильный - это возвращает кортеж значений, а не список кортежей. Что он делает, так это то, что он выполняет итерации по списку (следуя хвостам, используя List.tail), и когда он достигает конца, он возвращает единственный элемент каждого из списков, который является "e" и 5.

Первым шагом к исправлению может быть добавление аннотаций типов. Это заставит вас вернуть список в ветке then. Если у вас есть два одноэлементных списка ["e"] и [5], вы хотите вернуть ["e", 5]:

let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
    if List.length a = 1 then [List.head a , List.head b]
    else zip (List.tail a , List.tail b) 

Это все еще не правильно - в случае else вы просто смотрите на хвосты, но вы игнорируете головы. Вам нужно получить доступ к head и объединить его со списком, возвращаемым из вашего рекурсивного вызова:

let rec zip (a:'a list , b:'b list) : list<'a * 'b> =
    if List.length a = 1 then [List.head a , List.head b]
    else (List.head a, List.head b) :: zip (List.tail a , List.tail b) 

Это работает, но использование if .. then .. else в этом случае неэлегатно. Ответ Филипе показывает, как сделать это лучше с сопоставлением с образцом.

1 голос
/ 08 марта 2020
let rec zip (a, b) =
    match (a, b) with
    | ha :: ta, hb :: tb -> (ha, hb) :: zip (ta, tb)
    | _, _ -> []
...