ramda.js-如何将fn应用于集合的子集

时间:2019-07-30 15:28:24

标签: javascript functional-programming ramda.js

我正在寻找一种将函数(例如,assoc)应用到集合子集的优雅方法,但是要返回完整的集合。有人提出了类似的想法,如lensWhere

在JS中执行此操作的一种方法是:

const applyToSubset = fn => predicate => col =>
    col.filter(item => !predicate(item))
    .concat(
        col.filter(item => predicate(item))
        .map(fn)
    )

当然,这种方法对集合进行了重新排序,这并不理想。

使用ramda.js或功能性习语是否有更标准的方法?

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

快速回顾一下,您想partition原始列表,并且左边的谓词不匹配,右边的Tuple(non-matches, matches)匹配。然后将fn仅应用于匹配项。最后再次整理列表。

const applyToSubset = R.curry((fn, predicate, list) => R.pipe(
  R.partition(R.complement(predicate)),
  R.over(R.lensIndex(1), R.map(fn)),
  R.flatten
)(list));
    
    
const predicate = n => n >= 5;
const square = n => n * n;
const list = [2, 3, 4, 5, 6, 7, 8];

console.log(
  'result',
  applyToSubset(square, predicate, list)
);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>


如果您对分区不感兴趣,但想保持原始数组顺序...则可以尝试以下方法:

const applyToSubset = R.converge(R.map, [
  (fn, filter) => R.when(filter, fn),
  R.nthArg(2),
]);
    
    
const predicate = n => n >= 5;
const square = n => n * n;
const list = [2, 3, 4, 5, 6, 7, 8];

console.log(
  'result',
  applyToSubset(square, predicate, list)
);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

答案 1 :(得分:0)

使用Array#map仍然是一种非常简单的方法:只需检查每个项目,然后将整个功能f应用于将true应用于每个元素的元素,并将它们应用于predicate

const applyToSubset = f => predicate => xs => 
    xs.map (x => predicate (x) ? f (x) : x)
    
const { assoc } = R
    
    
const input = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]
const output = applyToSubset (assoc ('y') (1)) (({ x }) => x > 1) (input)

console.log (output)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>