F #: Как проверить равенство элементов последовательности / списка?

#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
 

Там вы разбиваете свой список на кортежи и проверяете, равны ли кортежи. Транзитивно это означает, что все элементы равны.