ramda.js - 如何将 fn 应用于集合的子集
ramda.js - how to apply a fn to subset of a collection
我正在寻找一种将函数(例如 assoc
)应用于集合的子集但 return 完整集合的优雅方法。类似的想法被提出为 lensWhere.
在 JS 中执行此操作的一种方法是:
const applyToSubset = fn => predicate => col =>
col.filter(item => !predicate(item))
.concat(
col.filter(item => predicate(item))
.map(fn)
)
当然,这种方法会重新排序集合,这并不理想。
是否有更标准的方法来使用 ramda.js 或功能习语来做到这一点?
感谢您的帮助!
我可能会用 Ramda 这样写:
const applyToSubset = (fn) => (pred) => map (when (pred, fn))
console .log (
applyToSubset (triple) (isOdd) ([8, 6, 7, 5, 3, 0, 9])
) //~> [8, 6, 21, 15, 9, 0, 27]
console .log (
applyToSubset (triple) (isOdd) ({a: 8, b: 6, c: 7, d: 5, e: 3, f: 0, g: 9})
) //~> {a: 8, b: 6, c: 21, d: 15, e: 9, f: 0, g: 27}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {map, when, multiply} = R
const isOdd = n => n % 2 == 1;
const triple = multiply(3)
</script>
虽然可能有一些无意义的方式来做到这一点,但它已经非常可读了。
快速回顾一下,您想要 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>
还有一种使用 Array#map
的非常简单的方法:只需检查每个项目并将整个函数 f
应用于那些输出 true
的元素,当将每个元素应用于 [=15] 时=].
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>
我正在寻找一种将函数(例如 assoc
)应用于集合的子集但 return 完整集合的优雅方法。类似的想法被提出为 lensWhere.
在 JS 中执行此操作的一种方法是:
const applyToSubset = fn => predicate => col =>
col.filter(item => !predicate(item))
.concat(
col.filter(item => predicate(item))
.map(fn)
)
当然,这种方法会重新排序集合,这并不理想。
是否有更标准的方法来使用 ramda.js 或功能习语来做到这一点?
感谢您的帮助!
我可能会用 Ramda 这样写:
const applyToSubset = (fn) => (pred) => map (when (pred, fn))
console .log (
applyToSubset (triple) (isOdd) ([8, 6, 7, 5, 3, 0, 9])
) //~> [8, 6, 21, 15, 9, 0, 27]
console .log (
applyToSubset (triple) (isOdd) ({a: 8, b: 6, c: 7, d: 5, e: 3, f: 0, g: 9})
) //~> {a: 8, b: 6, c: 21, d: 15, e: 9, f: 0, g: 27}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {map, when, multiply} = R
const isOdd = n => n % 2 == 1;
const triple = multiply(3)
</script>
虽然可能有一些无意义的方式来做到这一点,但它已经非常可读了。
快速回顾一下,您想要 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>
还有一种使用 Array#map
的非常简单的方法:只需检查每个项目并将整个函数 f
应用于那些输出 true
的元素,当将每个元素应用于 [=15] 时=].
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>