Упрощение
Да, есть несколько более простой способ написать midElement
. Это чувствует себя немного чище:
const div2 = divide (__, 2)
const lengthDiv2 = compose (floor, div2, length)
const midElement = chain (nth, lengthDiv2)
console.log (midElement ([8, 6, 7, 5, 3, 0, 9])) //=> 5
console.log (midElement ([8, 6, 7, 5, 3, 0])) //=> 5
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script><script>
const {divide, __, compose, length, chain, nth} = R
const {floor} = Math </script>
(Мы выбираем nth
вместо prop
здесь только потому, что это семантически более правильно. nth
задается c для массивов и их индексов. prop
работает только из-за совпадения того, что Javascript строит свои массивы поверх простых объектов.)
chain
- это интересная функция. Вы можете найти более подробную информацию в спецификации FantasyLand . Но для наших случаев важным моментом является то, как он работает с функциями.
chain (f, g) //=> (x) => f (g (x)) (x)
И это объясняет, как (здесь по крайней мере) это более простая альтернатива converge
.
Обратите внимание, что эта версия - как ваш оригинал - выбирает второе из двух центральных значений, когда список имеет четную длину. Я обычно нахожу, что мы более естественно выбираем первое. То есть, например, midpoint([3, 6, 9, 12])
обычно будет 6
. Чтобы изменить это, мы могли бы просто добавить операцию декремента перед делением:
const midpoint = chain(nth, compose(floor, divide(__, 2), dec, length))
Но Почему?
Однако Рамда не предлагает здесь много полезного. Рамда (отказ от ответственности: я один из его главных авторов) предлагает помощь по многим проблемам. Но это инструмент, и я бы не советовал использовать его, кроме случаев, когда он делает ваш код чище.
И эта версия мне кажется намного проще для понимания:
const midpoint = (xs) => xs[Math.floor ((xs.length / 2))]
console.log (midpoint ([8, 6, 7, 5, 3, 0, 9])) //=> 5
console.log (midpoint ([8, 6, 7, 5, 3, 0])) //=> 5
Или эта версия, если вы хотите поведение при уменьшении выше:
const midpoint = (xs) => xs[Math.floor (((xs.length - 1) / 2))]
console.log (midpoint ([8, 6, 7, 5, 3, 0, 9])) //=> 5
console.log (midpoint ([8, 6, 7, 5, 3, 0])) //=> 7
Другой вариант
Но существует множество способов написания такой функции. Хотя я не очень рекомендую это, поскольку его производительность не может сравниться, рекурсивное решение очень элегантно:
// choosing the first central option
const midpoint = (xs) => xs.length <= 2 ? xs[0] : midpoint (xs.slice(1, -1))
// choosing the second central option
const midpoint = (xs) => xs.length <= 2 ? xs[xs.length - 1] : midpoint (xs.slice(1, -1))
Они просто берут один из двух центральных элементов, если их не больше двух left и в противном случае рекурсивно принимает среднюю точку массива, оставшегося после удаления первого и последнего элементов.
Что запомнить
Я основатель Ramda и горжусь библиотекой. Но нужно помнить, что это просто библиотека. Это должно облегчить определенный стиль кодирования, но не должно диктовать какой-либо конкретный стиль. Используйте его, когда он делает ваш код проще, удобнее в обслуживании, более согласованным или более производительным. Никогда не используйте его просто потому, что можете.