Сравнение значений в цикле внутри функции

Я хочу сделать функцию, которая принимает список целых чисел в качестве аргумента, сравнивает каждое значение и возвращает наибольшее значение. В C# я просто перебираю каждое значение в списке, сохраняю наибольшее в переменной и возвращаю его, я надеюсь, что F# работает аналогично, но синтаксис для меня довольно сомнительный, вот как выглядит мой код. Также max2 - это функция, которая сравнивает 2 значения и возвращает наибольшее.

let max_list list = 
    let a = 0 : int
    match list with
    | head :: tail -> (for i in list do a = max2 i a) a
    | [] -> failwith "sry";; 

3 ответа

Решение

Вы могли бы использовать mutable переменная и написать код, используя for цикл, как в C#. Однако, если вы делаете это для изучения F# и функциональных концепций, тогда стоит использовать рекурсию.

В этом случае рекурсивная функция немного длиннее, но она демонстрирует ключевые концепции, включая сопоставление с образцом, поэтому изучение трюков будет полезным при написании более сложного кода F#.

Основная идея состоит в том, чтобы написать функцию, которая принимает наибольшее из найденных значений и рекурсивно вызывает себя, пока не достигнет конца списка.

let max_list list = 
  // Inner recursive function that takes the largest value found so far
  // and a list to be processed (if it is empty, it returns 'maxSoFar')
  let rec loop maxSoFar list = 
    match list with
    // If the head value is greater than what we found so far, use it as new greater
    | head::tail when head > maxSoFar -> loop head tail
    // If the head is smaller, use the previous maxSoFar value
    | _::tail -> loop maxSoFar tail
    // At the end, just return the largest value found so far
    | [] -> maxSoFar
  // Start with head as the greatest and tail as the rest to be processed
  // (fails for empty list - but you could match here to give better error)
  loop (List.head list) (List.tail list)

В заключение отметим, что это будет медленно, потому что используется общее сравнение (через интерфейс). Вы можете сделать функцию быстрее, используя let inline max_list list = (...), Таким образом, код будет использовать собственную инструкцию сравнения при использовании с такими примитивными типами, как int (это действительно особый случай - проблема действительно возникает только при общем сравнении)

Также знайте, что вы можете написать хороший однострочный текст, используя Reduce:

let max_list list = List.reduce (fun max x -> if x > max then x else max)

Если ваше намерение состоит в том, чтобы найти максимальное значение элементов в списке, где значение элементов найдено функцией max2, тогда этот подход работает:

let findMax list =
   list 
   |> List.map (fun i -> i, max2 i)  
   |> List.maxBy snd
   |> fst
Другие вопросы по тегам