функция для возврата индекса наибольшего соседа - PullRequest
2 голосов
/ 11 июля 2010

F # функция

Проблема:

с учетом списка предметов, например ::100100

["5";"10";"2";"53";"4"]

и поисковый индекс. Мне нужна функция, которая сравнивает текущий заданный индекс со своим соседом, возвращая самый большой индекс

Пример:

  • Данный индекс 1 вернет значение индекса 2 (потому что 10 больше 5).
  • Если индекс 4 вернет индекс 4 (потому что 53 больше 4)

В настоящее время это моя функция. Не компилируется:

let GetMaxNode (x:Array) Idx = if x.[Idx] > x.[Idx+1] then  Idx else If  x.[Idx] < x.[Idx+1] then  Idx+1

Ошибки, которые я получаю для всех х ':

The field, constructor or member 'Item' is not defined (FS0039)

А также второй If:

The value or constructor 'If' is not defined (FS0039)

Я подозреваю, что все еще думаю процедурно, я думал об использовании сопоставления с образцом, однако я не был достаточно уверен в синтаксисе, чтобы попробовать это.

Пожалуйста, не могли бы вы также объяснить и ответ , так как я пытаюсь выучить F #, только решение мне не сильно поможет.

Ответы [ 4 ]

3 голосов
/ 11 июля 2010

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

Функциональной версией вашего вопроса будет, например, создание списка, содержащего true, когда элемент в текущей позиции больше следующего, и false, когда он меньше. Для ваших данных это даст:

let data = [ 5;     10;   2;     53;   4 ]
let res  = [ false; true; false; true; ] // no item to compare '4' with 

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

let rec getMaxNodes data = 
  match data with 
  // list has at least two elements and current is larger
  | current::next::other when current >= next ->
      // process the rest of the list
      let rest = (getMaxNodes (next::other))
      // return 'true' followed by recursively processed rest of the list
      true::rest
  // list has at least two elements and current is smaller
  | current::next::rest ->
      // same as the previous case, but we return false
      false::(getMaxNodes (next::rest))
  | _ -> 
      // one element (so we cannot compare it with the next one)
      // or empty list, so we return empty list
      []

getMaxNodes data
3 голосов
/ 11 июля 2010

Вот код, основанный на вашем:

let GetMaxNode (x:_[]) idx = 
    if x.[idx] > x.[idx+1] then  
        idx 
    elif x.[idx] < x.[idx+1] then  
        idx+1 
    else
        idx // same, return this one

Основные изменения

  • для объявления типа массива, скажем <typename> [].В данном случае нам не важен тип, поэтому я использую _ как переменную типа "не волнует, пожалуйста, сделайте вывод, что мне нужно".
  • "else if" - этопишется elif в F #
  • нужен случай else, если равен
2 голосов
/ 11 июля 2010

Вот вариант ответа Брайана на соответствие шаблону.

let GetMaxNode (x:_[]) idx =
    match idx with
    | idx when x.[idx] > x.[idx+1] -> idx
    | idx when x.[idx] < x.[idx+1] -> idx + 1
    | idx -> idx // same, return this one

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

let GetMaxNode (x:_[]) = function
    | idx when x.[idx] > x.[idx+1] -> idx
    | idx when x.[idx] < x.[idx+1] -> idx + 1
    | idx -> idx // same, return this one
0 голосов
/ 11 июля 2010

Всякий раз, когда вы начинаете говорить об индексах, вам лучше всего придерживаться Arrays или ResizeArrays; Списки F # не подходят для операций с индексами, так как они имеют одинарную связь голова к хвосту. Это, как говорится, не так уж сложно написать этот алгоритм чисто функциональным путем, перемещаясь по списку с помощью рекурсивного цикла и отслеживая текущий индекс и текущий элемент.

let find elements index =
    //a local tail-recursive function hides implementation details
    //(cur::tail) is a pattern match on the list, i is the current index position
    let rec loop (cur::tail) i =
        if i = index then //when the current index matches the search index
            if cur >= tail.Head then i //compare cur to tail.Head (which is next)
            else (i+1)
        else loop tail (i+1) //else continue
    loop elements 0 //the entry point of loop and our return value

Используйте список целых чисел вместо строк, чтобы получить ожидаемые результаты (поскольку «10» на самом деле меньше, чем «5»):

> let x = [5;10;2;53;4];;
> find x 0;;
val it : int = 1
> find x 1;;
val it : int = 1
> find x 2;;
val it : int = 3
> find x 3;;
val it : int = 3
...