Есть ли альтернатива, чтобы получить средний элемент из массива с помощью Ramda? - PullRequest
0 голосов
/ 18 февраля 2020

Я попробовал этот код, и он дает желаемый результат:

const {
  __,
  compose,
  converge,
  divide,
  identity,
  length,
  prop
} = require("ramda");

const div2 = divide(__, 2);
const lengthDiv2 = compose(Math.floor, div2, length);
const midElement = converge(prop, [lengthDiv2, identity]);

console.log(midElement([1, 5, 4]); //5

Но я не знаю, есть ли другой способ получить свойство из массива, в частности, какая-то другая реализация midElement функции

Ответы [ 2 ]

0 голосов
/ 18 февраля 2020

Упрощение

Да, есть несколько более простой способ написать 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 и горжусь библиотекой. Но нужно помнить, что это просто библиотека. Это должно облегчить определенный стиль кодирования, но не должно диктовать какой-либо конкретный стиль. Используйте его, когда он делает ваш код проще, удобнее в обслуживании, более согласованным или более производительным. Никогда не используйте его просто потому, что можете.

0 голосов
/ 18 февраля 2020

Вы можете создать midElement, связав R.nth и lengthDiv2, потому что согласно документации R.chain (и @ScottSauyet):

Если второй аргумент является функцией, цепочка (f, g) (x) эквивалентна f (g (x), x).

В этом случае g равно lengthDiv2 , f - это R.nth, а x - это массив. Таким образом, результатом будет R.nth(lengthDiv2(array), array), который вернет средний элемент.

const { compose, flip, divide, length, chain, nth } = R;

const div2 = flip(divide)(2); // create the function using flip
const lengthDiv2 = compose(Math.floor, div2, length);
const midElement = chain(nth, lengthDiv2); // chain R.nth and lengthDiv2

console.log(midElement([1, 5, 4])); //5
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
...