Javascript Ramda:如何通过Curry、filtering和mapping来最小化计算资源?
我正在使用Ramda构建React应用程序。我对函数式编程还是新手(大约两个月) 我有如下联系人列表:Javascript Ramda:如何通过Curry、filtering和mapping来最小化计算资源?,javascript,arrays,functional-programming,currying,ramda.js,Javascript,Arrays,Functional Programming,Currying,Ramda.js,我正在使用Ramda构建React应用程序。我对函数式编程还是新手(大约两个月) 我有如下联系人列表: const contacts = [ { id: 1, firstName: 'Sven', lastName: 'Hillstedt', city: 'Aachen', company: '', position: 'Student', group: 'friends', tendency: 'maintain' },
const contacts = [
{
id: 1,
firstName: 'Sven',
lastName: 'Hillstedt',
city: 'Aachen',
company: '',
position: 'Student',
group: 'friends',
tendency: 'maintain'
},
{
id: 2,
firstName: 'David',
// ...
];
给定一个字符串,我需要过滤这个(非常长,10.000-100.000)列表。但是我只需要考虑钥匙firstName
,lastName
,city
,company
和position
。有一个数组包含以下内容:
const FIRST_NAME = 'firstName';
const LAST_NAME = 'lastName';
const CITY = 'city';
const COMPANY = 'company';
const POSITION = 'position';
export const stringFields = [FIRST_NAME, LAST_NAME, CITY, COMPANY, POSITION];
现在,我使用Ramda编写了以下函数,该函数接受一个字符串和一个联系人列表,映射到联系人的键上,选择相关的键并将其小写,然后返回过滤后的联系人:
import { any, filter, includes, map, pick, pipe, toLower, values } from 'ramda';
const contactIncludesValue = value =>
pipe(
pick(stringFields),
map(toLower),
values,
any(includes(value))
);
const filterContactsByValue = value => filter(contactIncludesValue(value));
正如您所看到的,这段代码很混乱(甚至认为它比强制执行要漂亮得多)。我多次咖喱value=>
,感觉不太好。我还质疑,这段代码是否只在联系人上迭代一次,是否有效
您如何过滤和映射(仅选择相关键+小写字母
)大量联系人列表,而无需重复两次或多次?有没有办法避免我的咖喱,写下这篇文章?这里有几点需要回应
- 即使这些评论有点刺耳,@zerkms说得对。除非您知道代码的性能实际上很差,否则尝试性能优化是没有意义的,尤其是当它使代码更难编写或维护时
- 您不会多次使用curry
value=>
。它只在前面使用,并且每次筛选列表时,部分应用您的值一次
- 您只需重复您的联系人一次。但在每一个字段中都有一个对
any
字段列表的调用。如果找到匹配项,这个函数会提前返回,因此计算调用数并不是件小事,但它可能是O(m*n)
,其中m
是字段数,n
是联系人数
这个版本的代码稍微精简一些。您可能会发现它更具可读性,也可能不会:
const contactIncludesValue = value =>
pipe(
props(stringFields),
map(toLower),
any(includes(value))
);
const filterContactsByValue = pipe(contactIncludesValue, filter);
请注意,props
比拾取(…)->值更方便,中间的映射(toLower)
也同样适用
您如何过滤和映射(仅选择相关键+小写)一个大型联系人列表,而无需重复两次或多次?有没有办法避免我的咖喱和写这个清洁剂
如果您需要一次性过滤和转换数据,我不知道如何单独使用filter
例如,这不会保留a
并对其进行转换:
const list=[
{a:'foo'},
{b:'bar'}
];
console.log(
过滤器(管道(映射(toUpper)、has('a')、列表)
);代码>
const{filter,pipe,map,toUpper,has}=R
R.innerJoin
无疑是最简洁的编写方式,但我不确定它的时间复杂性
const filter=value=>R.innerJoin(
//你可以在这里用小写等
(记录,属性)=>R.propEq(属性,值,记录),
R.。uuuuuuuuuuu,
['firstName','lastName','city','company','position'],
);
const onlySven=过滤器('Sven');
const onlygiusepe=过滤器('Giuseppe');
常数数据=[
{
id:1,
名字:“斯文”,
姓氏:“Hillstedt”,
城市:“亚琛”,
公司:'',
职位:'学生',
小组:"朋友",,
趋势:“保持”
},
// ...
];
console.log('Giuseppe',仅用于Giuseppe(数据));
log('Sven',onlySven(数据))代码>
每次性能优化都应该从基准测试和/或评测开始。请提供这些结果。@zerkms这取决于,在我的MacBook Pro浏览器中,这几乎不值得注意,但在android手机上,如果您多次重复列表,您可以看到一圈。如果您没有基线,您无法证明“改进”解决方案实际上改进了任何东西。如果你喜欢把时间浪费在随机的事情上,并希望它能神奇地改善任何事情——对你有好处,玩得开心:-)例如,在你的例子中,问题很可能不是迭代多次,而是分配大量临时数组并线性搜索它们。但是,嘿,请改进循环的数量(因为你猜到了,对吧?)如果any(包括(值))
readany(eqBy(toLower,value))
则可以删除map(toLower)
。这意味着两件事:1)您不需要事先将所有内容都小写(非常小的改进)和2)value
本身不需要小写。