#f#
#f#
Вопрос:
Я хотел бы проверить, все ли элементы в списке / последовательности чему-то равны
Например, последовательность целых чисел.
Я хотел бы проверить, равен ли ВЕСЬ элемент последовательности одному и тому же числу.
Мое решение пока выглядит как решение для императивного программирования.
let test seq =
if Seq.forall(fun num -> num =1) then 1
elif Seq.forall(fun num-> num = 2) then 2
else None
Ответ №1:
Ваше решение отлично! Проверка того, что все элементы последовательности имеют некоторое значение, — это не то, что вы можете красиво выразить с помощью сопоставления с образцом — вы должны использовать when
предложение, но это делает то же самое, что и ваш код (но с более длинным синтаксисом). В подобных случаях нет абсолютно ничего плохого в использовании if
.
Вы можете расширить сопоставление с образцом, определив пользовательские активные шаблоны, что дает вам хороший вариант здесь. Это довольно продвинутый F #, но вы можете определить пользовательский шаблон ForAll n
, который выполняется успешно, когда ввод представляет собой последовательность, содержащую только n
значения:
let (|ForAll|_|) n seq =
if Seq.forall (fun num -> num = n) seq then Some() else None
Обратите внимание, что успех представлен как Some
, а неудача как None
. Теперь вы можете очень хорошо решить свою проблему, используя сопоставление шаблонов:
let test = function
| ForAll 1 -> Some 1
| ForAll 2 -> Some 2
| _ -> None
Это выглядит довольно красиво, но оно опирается на более продвинутые функции — я бы сделал это, если это то, что вам нужно в нескольких местах. Если бы мне это нужно было только в одном месте, я бы выбрал обычный if
.
Ответ №2:
Вы можете переписать его, используя сопоставление с шаблоном с предложением guard:
let testList = [2;2;2]
let isOne x = x = 1
let isTwo x = x = 2
let forAll = function
| list when list |> List.forall isOne -> Some 1
| list when list |> List.forall isTwo -> Some 2
| _ -> None
let res = forAll testList //Some 2
Ответ №3:
Вместо функции вы могли бы использовать частичное применение к оператору equals .
> let yes = [1;1;1];;
val yes : int list = [1; 1; 1]
> let no = [1;2;3];;
val no : int list = [1; 2; 3]
> yes |> List.forall ((=) 1);;
val it : bool = true
> no |> List.forall ((=) 1);;
val it : bool = false
Может быть, это выглядит более функционально? И я думаю, вам следует вернуться Some 1
в свой код, иначе вы получите ошибки типа, поскольку Option и int не одного и того же типа…
Если вы хотите проверить, все ли элементы равны (а не только если они равны некоторой константе), вы могли бы сделать это:
> [1;2] |> List.pairwise |> List.forall (fun (a,b) -> a = b)
;;
val it : bool = false
> [1;1;1] |> List.pairwise |> List.forall (fun (a,b) -> a = b)
;;
val it : bool = true
Там вы разбиваете свой список на кортежи и проверяете, равны ли кортежи. Транзитивно это означает, что все элементы равны.