我喜欢 Ramda,但有时我会在看似简单的事情上犯错误。 我所拥有的是我需要研究的地点和单词的列表(它们的indexOf必须等于0)以生成搜索建议列表,因此例如,给出下面的列表,我想向用户建议当他们在搜索框中输入“aber”时,会显示所有 3 个区域(按名称),但如果输入“nor”,则只会显示阿伯丁北。
[
{
name: "Aberavon",
words: [ "aberavon" ]
},
{
name: "Aberconwy",
words: [ "aberconwy" ]
},
{
name: "Aberdeen North",
words: [ "aberdeen", "north" ]
},
]
我设法让“正确”的东西运行,通过控制台日志获取结果,但是我似乎没有得到过滤的项目。我的代码如下所示,控制台日志将正确显示单词的迭代以及与术语开头匹配的索引,但我从未将对象从过滤器中取出。我试图让它变得更实用,甚至更不起作用,但到目前为止还没有结果!这是我的代码:
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 值bool
第 1 步:检查单词
是否与术语
匹配
目前,您已经定义了一个基本上是您的“开头为”测试的函数:
R.equals ( word.indexOf ( term ), 0 )
此函数需要两个字符串才能工作:word
和 term
。 (从技术上讲,它们可以是任何实现 indexOf
的东西,但让我们坚持看这个例子)
我首先测试这个方法并给它一个名称,这样你就知道这部分已经“完成”并且可以工作了。
const startsWith = term => word => word.indexOf(term) === 0;
(稍后,您可以重写它以使用 Ramda API 并包含其他功能,例如区分大小写。您可能还想注释诸如 string -> string -> bool
之类的内容,但是再说一遍,我不知道 Ramda 方式)
第 2 步:检查某个字符串是否与术语
匹配
现在您可以检查字符串是否与某个术语匹配,您需要查明字符串数组中的至少一个字符串是否与某个术语匹配。
用纯 JavaScript 表示:
const anyStartsWith = term => arr => arr.some(startsWith(term));
我认为 Ramda 的等价物是 R.any
:
const anyStartsWith = term => R.any(startsWith(term));
再次测试此方法,看看它的性能是否符合您的预期。
第 3 步:检查地点
是否与术语匹配
这是最复杂的一步。我们需要从具有 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 中,它可能类似于 this ,但同样,我不是专家。我会将 Ramda 标签添加到您的问题中,这使得很可能有人会出现向您展示 Ramda 方法:)
关于javascript - 使用Ramda(或其他功能库)使用indexOf过滤大数组对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43977439/