#.net #f# #f#-interactive
#.net #f# #f # -интерактивный
Вопрос:
Я новичок в мире F #. У меня есть вопрос относительно удаления элементов в списке. Предположим, у вас есть произвольный список, скажем
let list1 = [0;1;2;0;3;4;0;0]
Я хочу удалить все последние нули, чтобы список стал
list1 = [0;1;2;0;3;4]
Я попытался перевернуть список и проверить, равен ли head нулю, а затем выполнить рекурсивный вызов хвоста
let rec remove ps = if List.rev(ps).Head <> 0 then ps else remove(ps.Tail);;
Однако я либо получаю код ошибки пустого списка, либо он просто возвращает исходный список.
Любая помощь приветствуется
Ответ №1:
Ваша «ошибка» заключается в следующем. Сначала вы переворачиваете список, поэтому:
[0;0;4;3;0;2;1;0]
Затем вы проверяете, начинается ли он с 0
— это так. Затем вы передаете хвост исходного списка. Итак, вы удалили первое число, а не последнее:
[1;2;0;3;4;0;0]
Поскольку вы никогда не удаляете последний ноль, он будет возвращаться true
при тестировании 0
, пока вы не закончите вызов remove
с пустым списком. Затем вы создаете исключение, пытаясь получить Head
из пустого списка.
Это исправляет ошибку, при которой рекурсивный вызов с хвостом перевернутого списка (то есть без последнего номера) снова возвращается к исходному порядку:
let rec remove ps =
let reversed = List.rev ps
if reversed.Head <> 0 then ps else remove (List.rev reversed.Tail)
Использование сопоставления с образцом может быть немного более идиоматичным. Это также не приведет к появлению пустого списка:
let rec remove list =
match List.rev list with
| 0::xs -> remove (List.rev xs)
| _ -> list
Вы также можете сделать то же самое без рекурсии. Переверните список один раз, пропускайте до тех пор, пока значение не 0
изменится, затем снова переверните его:
let remove list =
list
|> List.rev
|> List.skipWhile (fun x -> x = 0)
|> List.rev
Комментарии:
1. Большое вам спасибо и спасибо за объяснение, а не просто за чистый код.