#arrays #rescript
#массивы #rescript
Вопрос:
Допустим, я хочу выполнить итерацию по массиву способом, который плохо поддерживается Js
/ Belt
стандартными библиотечными функциями. Например, возможно, мне нужно проверять пары элементов за раз. Со списком это просто сделать в рекурсивном стиле:
let rec findDouble = (list) => switch list {
| list{a, b, ..._} when a == b => a
| list{_, b, ...rest} => findDouble(list{b, ...rest})
| _ => 0
}
list{7, 9, 10, 10, 11, 13} |> findDouble |> Js.log // 10
Однако ReScript, похоже, мягко не поощряет списки в пользу массивов (см.: более неуклюжий синтаксис списка и отсутствие эквивалентов списка некоторых стандартных библиотечных функций, таких как Belt.Map.fromArray
), поэтому я не уверен, что преобразование массива в список только для использования этого стиля является идиоматичным — особенно если функция создает список, который затем должен превратиться обратно в массив.
Конечно, я могу использовать изменчивость для реализации функции традиционным императивным способом:
let findDouble = (arr) => {
let idx = ref(1)
let answer = ref(0)
while (idx.contents < Js.Array.length(arr)) amp;amp; (answer.contents == 0) {
if arr[idx.contents] == arr[idx.contents - 1] {
answer := arr[idx.contents]
}
idx := idx.contents 1
}
answer.contents
}
[7, 9, 10, 10, 11, 13] |> findDouble |> Js.log // 10
Но это некрасиво и противоречит функциональным основам ReScript.
Каков чистый, идиоматический способ реализации этой функции?
Ответ №1:
Вы все еще можете использовать рекурсию, только с увеличением индекса вместо использования конца списка:
let findDouble = arr => {
let rec loop = idx =>
if idx >= Array.length(arr) {
0
} else if arr[idx] == arr[idx - 1] {
arr[idx]
} else {
loop(idx 1)
}
loop(1)
}