有没有其他方法可以使用 Ramda 从数组中获取中间元素?

Is there alternative to get middle element from array using Ramda?

我试过这段代码,它产生了我想要的结果:

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 函数的其他一些实现?

您可以通过链接 R.nth and lengthDiv2 because according to R.chain 文档(和@ScottSauyet)来创建 midElement

If second argument is a function, chain(f, g)(x) is equivalent to f(g(x), x).

在这种情况下 glengthDiv2f 是 R.nth,x 是数组。因此,结果将是 R.nth(lengthDiv2(array), array),这将是 return 中间项。

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>

简化

是的,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 over prop 只是因为它在语义上更正确。nth 特定于数组及其索引。prop 之所以起作用只是因为 Javascript 在普通对象之上构建它的数组。)

chain is an interesting function. You can find many more details in its FantasyLand specification。但对于我们的案例,重要的一点是它如何与函数一起工作。

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))

但是为什么呢?

然而,Ramda 在这里并没有提供太多有用的东西。 Ramda(免责声明:我是其主要作者之一)为许多问题提供帮助。但它是一个工具,我不建议使用它,除非它能让你的代码更干净。

这个版本在我看来更容易理解:

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))

如果剩下的不超过两个,则这些只取两个中心元素中的一个,否则递归取删除第一个和最后一个元素后剩余的数组的中点。

要记住什么

我是 Ramda 的创始人,我为这个库感到自豪。但我们需要记住,它只是一个图书馆。它应该使某种编码风格更容易,但它不应该规定任何特定的风格。当它使您的代码更简单、更易于维护、更一致或更高效时,请使用它。永远不要仅仅因为可以就使用它。