Я предлагаю разбить это на более мелкие части.Вместо одной функции, которая является сложной и трудной для отладки, у вас будет множество функций, которые легко написать и отладить.Меньшие функции проще тестировать и использовать в других частях вашей программы -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Теперь у нас есть minmax
.Уникальным для этой реализации является то, что он находит минимальное и максимальное значения, используя только один обход входного массива -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax ([]) // [ Infinity, -Infinity ]
)
По умолчанию minmax
возвращает list
изминимальное и максимальное значения.Мы можем подключить min и max напрямую к функции range
, которая может быть более полезной для нас, как мы увидим позже -
const range = (m, n) =>
m > n
? []
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax ([], range) // []
)
Теперь, когда мы можем найти min и max длявход, создать диапазон между двумя, все, что осталось, это вычисление lcm
значений в диапазоне.Взятие множества значений и приведение их к одному значению выполняется с помощью .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Оберните это в функцию, и все готово -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Проверьте результат в вашем собственном браузере ниже -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
? []
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Выше minmax
определяется с использованием стиля передачи продолжения.Мы сохраняем дополнительные вычисления, передавая range
в качестве указанного продолжения (then
).Однако мы можем вызвать minmax
без указания продолжения и распространить (...
) промежуточное значение до range
.Любая программа может иметь больше смысла для вас.Результат тот же -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
та же свинья, другая ферма
smallestCommons
- это просто сокращение диапазона [min,max]
- @ Carcigenicate
Надеюсь, это помогает увидеть один и тот же результат с нескольких подходов: D
Sourface
Некоторые люди презирают приведенную выше реализацию minmax
независимо от ее элегантности и гибкости.Теперь, когда мы немного лучше понимаем сокращение, мы можем показать, как лучше реализовать minmax
с помощью прямого стиля -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here