繁体   English   中英

使用indexOf使用Ramda(或其他功能库)过滤大型对象数组。

[英]Filtering big array of Objects with Ramda (or other functional library) using indexOf?

我爱Ramda,但有时我偶然发现一些看似简单的事情。 我所拥有的是我需要研究的地点和单词的列表(它们的indexOf必须等于0)以生成搜索建议列表,因此,例如,给定以下列表,我想向用户建议在搜索框中输入“ aber”时,所有3个区域(按名称),但如果输入“ nor”,则只有北阿伯丁。

[
  {
    name: "Aberavon",
    words: [ "aberavon" ]
  },
  {
    name: "Aberconwy",
    words: [ "aberconwy" ]
  },
  {
    name: "Aberdeen North",
    words: [ "aberdeen", "north" ]
  },
]

我设法通过控制台日志运行“正确的”东西来获取结果,但是我似乎没有得到过滤的项目。 我的代码看起来像这样,控制台日志将正确显示遍历单词和indexOf匹配术语开头的迭代,但是我从不从过滤器中取出对象。 我试图使它更具功能性和非功能性,到目前为止没有任何结果! 这是我的代码:

var matches = R.filter ( function ( x ) { R.map ( function ( word ) {
        console.log ( word );
        console.log ( word.indexOf ( term ) === 0 );
        R.equals ( word.indexOf ( term ), 0 )
    } ) ( x.words ) } ) ( json );

不是Ramda专家,但我可能会提供帮助。

传递给R.filter的函数(第一个参数)应采用一个object并返回bool

关键是要以可读和可重用的方式创建此方法。 最终,您将得到如下结果:

  • 从对象{}到字符串数组[string]
  • 从字符串数组[string]转到布尔布尔bool

步骤1:检查wordterm匹配

当前,您已经定义了一个函数,该函数基本上就是您的“开始于”测试:

R.equals ( word.indexOf ( term ), 0 )

该函数需要两个字符串才能工作: wordterm (从技术上讲,它们可以是实现indexOf任何东西,但让我们坚持这个示例)

我将从测试此方法并为其命名开始,以便您知道此部分“完成”并且可以正常工作。

const startsWith = term => word => word.indexOf(term) === 0;

(稍后,您可以重写此代码以使用Ramda API并包含其他功能,例如区分大小写(不区分大小写)。您可能还想注释诸如string -> string -> bool ,但是同样,我不知道Ramda的方式)

步骤2:检查某些字串是否符合term

现在您可以检查字符串是否与术语匹配,接下来,您需要确定字符串数组中至少有一个字符串与术语匹配。

用简单的javascript:

const anyStartsWith = term => arr => arr.some(startsWith(term));

我认为R.any等效为R.any

const anyStartsWith = term => R.any(startsWith(term));

再次,测试此方法,并查看其性能是否如您所愿。

步骤3:检查Place符合条件

这是最复杂的步骤。 我们需要从具有words属性的object转到我们之前定义的过滤器方法可以处理的对象。

const placeMatchesTerm = term => place =>
  anyStartsWith(term) (place.words);

步骤4:筛选

现在,我们有了一个接受术语的函数,并返回一个接受Place的函数。 我们可以使用它直接过滤位置数组:

const myPlaces = [ /* ... */ ];
const filter = (term, arr) => 
  arr.filter(placeMatchesTerm(term));

const aber = filter("aber", myPlaces);
const nor = filter("nor", myPlaces);

在一个有效的示例中(没有Ramda)

 // string -> string -> bool const startsWith = term => word => word.indexOf(term) === 0; // string -> [string] -> bool const anyStartsWith = term => arr => arr.some(startsWith(term)); // string -> {} -> bool const placeMatchesTerm = term => place => anyStartsWith(term) (place.words); // string -> [{}] -> bool const filter = term => arr => arr.filter(placeMatchesTerm(term)); const aber = filter("aber")(getPlaces()); const nor = filter("nor")(getPlaces()); console.log("'Aber' matches", aber.map(p => p.name)); console.log("'Nor' matches", nor.map(p => p.name)); // Data function getPlaces() { return [{name:"Aberavon",words:["aberavon"]},{name:"Aberconwy",words:["aberconwy"]},{name:"Aberdeen North",words:["aberdeen","north"]}]; } 

在Ramda中,可能是这样的 ,但是同样,我也不是专家。 我将在您的问题中添加Ramda标记,这很可能会有人出现来向您展示Ramda的方式:)

我相当喜欢上一个答案,但是如果您想了解Ramda的工作方式,这就是我的解决方案:

const startsWith = R.curry((term, word) => word.indexOf(term) === 0);
const anyStartsWith = R.curry((term, words) => R.any(startsWith(term), words));
const anyWordMatches = R.curry(
  (term, place) => anyStartsWith(term, R.prop('words', place))
);
const anyPlaceMatches = R.curry(
  (term, places) => R.filter(anyWordMatches(term), places)
);

anyPlaceMatches('nor', json); 
//=> [ <Aberdeen North> ]
anyPlaceMatches('aber', json); 
//=>[ <Aberavon>, <Abercrombie>, <Aberdeen North> ]

尽管所有这些都可能是毫无意义的,但我没有看到它的意义。

您可以在Ramda REPL中看到所有这些。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM