我有一个商店列表和一个id列表:
var stores = [{id: '1', name: 'first store'}, {id: '2', name: 'second store'}, {id: '3', name: 'third store'}];
var ids = ['1', '2'];
我想获取与列表中的ID匹配的商店名称:
["first store", "second store"]
以下是我提出的建议:
var filterStoresById = R.intersectionWith(R.useWith(R.equals, R.view(R.lensProp('id'))));
var extractNames = R.map(R.view(R.lensProp('name')));
extractNames(filterStoresById(stores,ids));
我的目标是学习函数式编程概念,同时生成我可以在现实生活中使用的代码,但我不认为我的解决方案是可读的也不是高效的(我迭代两次),所以改进可能是什么对这段代码做了什么?
答案 0 :(得分:3)
你的代码并不可怕,只是可读性稍差。
首先,要访问顶级属性,尤其是当您不重复使用访问方法时,使用prop(name)
比使用view(lensProp(name))
要简单得多。 Ramda对pluck
有map(prop)
。
其次,我发现通过功能组合构建的函数比通过嵌套的括号级更容易阅读。我通常更喜欢pipe
到compose
,但要么会这样做。
所以我会像这样修改你的代码:
var filterStoresById = R.intersectionWith(R.useWith(R.equals, R.prop('id')));
var storeNamesById = R.pipe(filterStoresById, R.pluck('name'));
storeNamesById(stores, ids);
这样做的一个好处是,如果您发现需要的不仅仅是名称,那么现在您拥有可重复使用的filterStoresById
功能。
另一个问题是表现。迭代两次肯定会受到惩罚。问题是,更清晰,更容易重构的代码是否值得。有一些技术可以将这样的代码转换成代码来执行相同的操作,但只迭代一次并避免使用中间容器。您可以查看these articles on transducers了解详情。
但我会避免担心这个,除非你能向自己证明这实际上是你应用程序中的性能问题。我假设每个人都知道Knuth错误引用“过早优化是所有邪恶的根源。”
答案 1 :(得分:1)
const stores = [
{id: '1', name: 'first store'},
{id: '2', name: 'second store'},
{id: '3', name: 'third store'},
]
const ids = ['1', '2']
const f =
R.pipe(R.innerJoin(R.flip(R.propEq('id'))), R.pluck('name'))
console.log(f(stores, ids))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>