我喜欢拉姆达,但有时我会偶然发现看似简单的事情。 我所拥有的是我需要查看的地方和单词列表(它们的indexOf必须等于0)以生成搜索建议列表,例如,给定下面的列表,我想向用户建议所有3个区域(按名称)在搜索框中键入“aber”但如果键入“nor”则仅为Aberdeen North。
[
{
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 );
答案 0 :(得分:3)
不是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并包含其他功能,例如case(in)灵敏度。您可能还想注释类似string -> string -> bool
的内容,但是我不知道Ramda方式)
term
匹配现在您可以检查字符串是否与术语匹配,您需要查明字符串数组中的至少一个字符串是否与术语匹配。
简单的javascript:
const anyStartsWith = term => arr => arr.some(startsWith(term));
我认为Ramda等价物是R.any
:
const anyStartsWith = term => R.any(startsWith(term));
再次,测试此方法,看看它是否像您希望的那样执行。
Place
是否与术语匹配这是最复杂的一步。我们需要从具有object
属性的words
转到我们之前定义的过滤器方法可以处理的内容。
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"]}];
}
在拉姆达,它可能像this,但同样,我不是专家。我会在你的问题中添加Ramda标签,这很可能会有人出现给你看Ramda的方式:)
答案 1 :(得分:0)
我非常喜欢上一个答案,但是如果你想看看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 中看到所有这些内容。