Javascript Ramda:如何通过Curry、filtering和mapping来最小化计算资源?

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' },

我正在使用Ramda构建React应用程序。我对函数式编程还是新手(大约两个月)

我有如下联系人列表:

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(包括(值))
read
any(eqBy(toLower,value))
则可以删除
map(toLower)
。这意味着两件事:1)您不需要事先将所有内容都小写(非常小的改进)和2)
value
本身不需要小写。