Как найти значение в списке, при котором встречается максимальное значение функции - PullRequest
3 голосов
/ 23 апреля 2011

Я хочу найти не только максимальное значение функции, примененной к списку (для которой я бы просто использовал List.maxBy), но также и значение в списке, в котором это произошло. Это похоже на довольно распространенную операцию, и учитывая богатство библиотек F # в целом, я совсем не удивлюсь, обнаружив, что это на самом деле уже доступно, но я не могу найти его, если оно есть!

Чтобы проиллюстрировать это на примере, я хочу иметь возможность отобразить список domain и функцию f

let domain = [0 .. 5]
let f x = -x * (x - 2)

до (1, 1) (поскольку функция, примененная к другому элементу списка, меньше 1).

Я впервые попробовал это:

let findMaximum domain f =
    let candidates = [ for x in domain do
                        yield x, f x ]
    let rec findMaximumHelper domain f currentMax =
        match domain with
        | [] -> currentMax
        | head::tail -> 
            let cand = f head
            match currentMax with
            | None ->
                let newMax = Some(head, cand)
                findMaximumHelper tail f newMax
            | Some(maxAt, possMax) ->
                let newMax =
                    if cand > possMax then Some(head, cand)
                    else Some(maxAt, possMax)
                findMaximumHelper tail f newMax
    findMaximumHelper domain f None

let answer = findMaximum domain f

В этот момент я понял, что это очень близко к операции fold , и сложил

let findMaximum2 domain f =
    let findMaximumHelper f acc x =
        let cand = f x
        match acc with
        | None -> Some(x, cand)
        | Some(maxAt, possMax) ->
            if cand > possMax then Some(x, cand)
            else Some(maxAt, possMax)
    List.fold (findMaximumHelper f) None domain

let answer2 = findMaximum2 domain f

вместо.

У меня вопрос: эти идиоматические F # способы решения этой проблемы или, действительно, есть лучший способ решения этой проблемы?

Ответы [ 2 ]

11 голосов
/ 23 апреля 2011

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

domain
|> Seq.map (fun x -> x, f x)
|> Seq.maxBy snd

Примечание: обновлено для использования Seq.map и Seq.maxBy вместо List.map и List.maxBy для решения проблемы @ ildjarn по созданию ненужного промежуточного списка.

5 голосов
/ 23 апреля 2011

Альтернатива ответу Стивена, которая позволяет избежать создания секунды List, с обменом выполнения f еще один раз:

domain
|> List.maxBy f
|> fun x -> x, f x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...