简体   繁体   English

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

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

I love Ramda, but sometimes i stumble in seemingly simple things. 我爱Ramda,但有时我偶然发现一些看似简单的事情。 What i have, is a list of places and words i need to look into (their indexOf must be equal to 0) to generate a list of search suggestions, so for example, given the list below, i would like to suggest to a user all 3 areas (by name) when they type 'aber' in the search box but only Aberdeen North if they type 'nor'. 我所拥有的是我需要研究的地点和单词的列表(它们的indexOf必须等于0)以生成搜索建议列表,因此,例如,给定以下列表,我想向用户建议在搜索框中输入“ aber”时,所有3个区域(按名称),但如果输入“ nor”,则只有北阿伯丁。

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

I managed to get the 'proper' thing running getting my results through console log, however i do not seem to get the filtered items. 我设法通过控制台日志运行“正确的”东西来获取结果,但是我似乎没有得到过滤的项目。 My code looks like this and the console logs will correctly show the iteration going through the words and the indexOf matching the start of a term but i never get my objects back out of the filter. 我的代码看起来像这样,控制台日志将正确显示遍历单词和indexOf匹配术语开头的迭代,但是我从不从过滤器中取出对象。 I tried to make it even more functional and even more non-functional to no result so far! 我试图使它更具功能性和非功能性,到目前为止没有任何结果! This is my code: 这是我的代码:

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 );

Not a Ramda expert, but I might be able to help. 不是Ramda专家,但我可能会提供帮助。

The function (first argument) you pass to R.filter should take an object and return a bool . 传递给R.filter的函数(第一个参数)应采用一个object并返回bool

The key is to create this method in a readable and reusable way. 关键是要以可读和可重用的方式创建此方法。 Eventually, you'll end up with something like: 最终,您将得到如下结果:

  • Go from an object {} to an array of strings [string] 从对象{}到字符串数组[string]
  • Go from an array of strings [string] to a boolean bool 从字符串数组[string]转到布尔布尔bool

Step 1: Checking if a word matches a term 步骤1:检查wordterm匹配

Currently, you have defined a function that is basically your "starts with" test: 当前,您已经定义了一个函数,该函数基本上就是您的“开始于”测试:

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

This function needs two strings to work: word and term . 该函数需要两个字符串才能工作: wordterm (Technically they could be anything that implements indexOf , but let's stick to the example) (从技术上讲,它们可以是实现indexOf任何东西,但让我们坚持这个示例)

I'd start by testing this method and giving it a name, so you know this part is "done" and works. 我将从测试此方法并为其命名开始,以便您知道此部分“完成”并且可以正常工作。

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

(Later, you can rewrite this to use the Ramda API and include other features like case (in)sensitivity. You might also want to annotate something like string -> string -> bool , but again, I don't know the Ramda way) (稍后,您可以重写此代码以使用Ramda API并包含其他功能,例如区分大小写(不区分大小写)。您可能还想注释诸如string -> string -> bool ,但是同样,我不知道Ramda的方式)

Step 2: Checking if some string matches a term 步骤2:检查某些字串是否符合term

Now that you can check if strings match a term, you'll need to find out if at least one string in an array of strings matches a term. 现在您可以检查字符串是否与术语匹配,接下来,您需要确定字符串数组中至少有一个字符串与术语匹配。

In plain javascript: 用简单的javascript:

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

I think the Ramda equivalent is R.any : 我认为R.any等效为R.any

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

Again, test this method and see if it performs like you want it to. 再次,测试此方法,并查看其性能是否如您所愿。

Step 3: Check if a Place matches a term 步骤3:检查Place符合条件

This is the most complicated step. 这是最复杂的步骤。 We need to go from an object with a words property to something our earlier defined filter methods can handle. 我们需要从具有words属性的object转到我们之前定义的过滤器方法可以处理的对象。

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

Step 4: Filtering 步骤4:筛选

Now, we have a function that takes a term and returns a function that takes a Place . 现在,我们有了一个接受术语的函数,并返回一个接受Place的函数。 This, we can use to filter our array of places directly: 我们可以使用它直接过滤位置数组:

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

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

In a working example (without Ramda) 在一个有效的示例中(没有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"]}]; } 

In Ramda, it might be something like this , but again, I'm no expert. 在Ramda中,可能是这样的 ,但是同样,我也不是专家。 I'll add the Ramda tag to your question which makes it pretty likely someone will show up to show you the Ramda ways :) 我将在您的问题中添加Ramda标记,这很可能会有人出现来向您展示Ramda的方式:)

I like the previous answer quite a bit, but if you want to see how a Ramda person does it, this would be my solution: 我相当喜欢上一个答案,但是如果您想了解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> ]

While all of this can probably be made point-free, I don't see the, ahem, point of that. 尽管所有这些都可能是毫无意义的,但我没有看到它的意义。

You can see all this in the Ramda REPL . 您可以在Ramda REPL中看到所有这些。

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

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