[英]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
word
与term
匹配 当前,您已经定义了一个函数,该函数基本上就是您的“开始于”测试:
R.equals ( word.indexOf ( term ), 0 )
该函数需要两个字符串才能工作: word
和term
。 (从技术上讲,它们可以是实现indexOf
任何东西,但让我们坚持这个示例)
我将从测试此方法并为其命名开始,以便您知道此部分“完成”并且可以正常工作。
const startsWith = term => word => word.indexOf(term) === 0;
(稍后,您可以重写此代码以使用Ramda API并包含其他功能,例如区分大小写(不区分大小写)。您可能还想注释诸如string -> string -> bool
,但是同样,我不知道Ramda的方式)
term
现在您可以检查字符串是否与术语匹配,接下来,您需要确定字符串数组中至少有一个字符串与术语匹配。
用简单的javascript:
const anyStartsWith = term => arr => arr.some(startsWith(term));
const anyStartsWith = term => R.any(startsWith(term));
再次,测试此方法,并查看其性能是否如您所愿。
Place
符合条件 这是最复杂的步骤。 我们需要从具有words
属性的object
转到我们之前定义的过滤器方法可以处理的对象。
const placeMatchesTerm = term => place =>
anyStartsWith(term) (place.words);
现在,我们有了一个接受术语的函数,并返回一个接受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.