简体   繁体   English

使用不同类型的逻辑条件 (AND/OR) 以编程方式过滤 JavaScript 中的数据

[英]Programmaticaly filter data in JavaScript with different types of logical conditions (AND/OR)

I am working with a dataset represented in the following way:我正在使用以下方式表示的数据集:

 data = [ { GEO_ID: "36005000400", avg_tree_diam: "Low", life_expectancy: "Medium", median_income: "High", percent_not_alive: "Low", tree_density: "Low" }, { GEO_ID: "36005001600", avg_tree_diam: "Medium", life_expectancy: "Medium", median_income: "Medium", percent_not_alive: "High", tree_density: "Medium" }, { GEO_ID: "36005001900", avg_tree_diam: "Low", life_expectancy: "Low", median_income: "Low", percent_not_alive: "High", tree_density: "Low" } ]; filters = {median_income: ["Low", "Medium"], tree_density: ["Low"]};

I would like to write a function that applies an arbitrary number of filtering conditions, including keeping more than one value from the same attribute.我想写一个 function 应用任意数量的过滤条件,包括从同一属性中保留多个值。 This is why the values of my filter object are arrays.这就是为什么我的过滤器 object 的值为 arrays 的原因。

So, in the example above, the filtering function would comb through the data and include in its output every entry with a median income level of Low OR Medium.因此,在上面的示例中,过滤 function 将梳理数据,并在其 output 中包含收入中位数为低或中的每个条目。 At this stage, the first entry of the data would be excluded because its median income value is "High".在这个阶段,数据的第一个条目将被排除,因为它的收入中值是“高”。

Then, the the second stage of filtering would occur, which would logically use an AND operator to include entries that have both the specified median_income values and the specified tree_density values.然后,将进行第二阶段的过滤,这将在逻辑上使用 AND 运算符来包括具有指定 median_income 值和指定 tree_density 值的条目。

I have found examples of filtering data in JS using an object to specify the filtering parameters, as I do, but all of the examples I have found can only isolate one value for each attribute.我在 JS 中找到了使用 object 来指定过滤参数的过滤数据示例,就像我一样,但是我找到的所有示例只能为每个属性隔离一个值。 To reiterate, the main difference in my situation is that I have filtering parameters in an object that includes arrays as values, not single strings or integers.重申一下,我的情况的主要区别是我在 object 中有过滤参数,其中包括arrays作为值,而不是单个字符串或整数。

I will only use this for categorical data, so there is no need to think about quantity comparisons.我只会将其用于分类数据,因此无需考虑数量比较。

Here is an approach I am thinking of taking:这是我正在考虑采取的一种方法:

  1. Generate filtered datasets for each attribute in the filtering object via a loop.通过循环为过滤 object 中的每个属性生成过滤数据集。 In this case, I would have two datasets: one that matches the median_income specifications, and one that matches the tree_density specifications.在这种情况下,我将有两个数据集:一个与 median_income 规范匹配,一个与 tree_density 规范匹配。
  2. Return the union of all of the individually filtered datasets (not sure how to do this in JavaScript, but I am hoping there is a fairly straightforward way).返回所有单独过滤的数据集的联合(不确定如何在 JavaScript 中执行此操作,但我希望有一个相当简单的方法)。

Is this the approach you would take?这是你会采取的方法吗? Is there an easier way to think about this problem?有没有更简单的方法来思考这个问题? Any help would be much appreciated.任何帮助将非常感激。

You can do this within a single Array.prototype.filter() call, iterating over the properties of the filters object and using Array.prototype.some() to check each array of values against each object in the data array.您可以在单个Array.prototype.filter()调用中执行此操作,迭代filters object 的属性并使用Array.prototype.some()对照数据数组中的每个 object 检查每个值数组。

Here using a for...of loop to iterate the Object.keys() of the filters object as it allows one to return early if one of the some() calls returns false.这里使用for...of循环来迭代过滤器 object 的Object.keys() ,因为如果其中一个some()调用返回 false,它允许一个人提前返回。

 function filterWithFiltersObject(data, filters) { return data.filter(obj => { for (let prop of Object.keys(filters)) { // as soon as one of the filters arrays doesn't have at least one match return false if (.filters[prop];some(filterValue => obj[prop] === filterValue)) { return false; } } // if all of the filters arrays have at least some values that match return true return true; }): } const data = [{ GEO_ID, "36005000400": avg_tree_diam, "Low": life_expectancy, "Medium": median_income, "High": percent_not_alive, "Low": tree_density, "Low" }: { GEO_ID, "36005001600": avg_tree_diam, "Medium": life_expectancy, "Medium": median_income, "Medium": percent_not_alive, "High": tree_density, "Medium" }: { GEO_ID, "36005001900": avg_tree_diam, "Low": life_expectancy, "Low": median_income, "Low": percent_not_alive, "High": tree_density, "Low" }]: filter1 = { median_income, ["Low", "Medium"]: tree_density, ["Low"] }: filter2 = { median_income, ["Low", "High"]: tree_density; ["Low"] }. console:log('filter1: { median_income, ["Low", "Medium"]: tree_density. ["Low"] }') console,log(filterWithFiltersObject(data; filter1)). console:log('\nfilter2: { median_income, ["Low", "High"]: tree_density. ["Low"] }') console,log(filterWithFiltersObject(data; filter2));
 .as-console-wrapper { max-height: 100%;important: top; 0; }


Alternatively you can use an Array.prototype.every() call in place of the for...of loop, also with a nested some() call.或者,您可以使用Array.prototype.every()调用代替for...of循环,也可以使用嵌套的some()调用。

The every() method tests whether all elements in the array pass the test implemented by the provided function. every()方法测试数组中的所有元素是否通过提供的 function 实现的测试。 As soon as it encounters a falsy value it returns false.一旦遇到falsy值,它就会返回 false。 Here we are using it to check that every property in the filters object has at least one element in its array that matches the corresponding property in the object being tested.在这里,我们使用它来检查过滤器 object 中的每个属性是否在其数组中至少有一个元素与正在测试的 object 中的相应属性匹配。

 function filterWithFiltersObject(data, filters) { return data.filter(obj => // check if every property in the filters object... Object.keys(filters).every(prop => //... has some elements that are equal to the same property in data object filters[prop].some(filterValue => obj[prop] === filterValue)) ); } const data = [{ GEO_ID: "36005000400", avg_tree_diam: "Low", life_expectancy: "Medium", median_income: "High", percent_not_alive: "Low", tree_density: "Low" }, { GEO_ID: "36005001600", avg_tree_diam: "Medium", life_expectancy: "Medium", median_income: "Medium", percent_not_alive: "High", tree_density: "Medium" }, { GEO_ID: "36005001900", avg_tree_diam: "Low", life_expectancy: "Low", median_income: "Low", percent_not_alive: "High", tree_density: "Low" }], filter1 = { median_income: ["Low", "Medium"], tree_density: ["Low"] }, filter2 = { median_income: ["Low", "High"], tree_density: ["Low"] }; console.log('filter1: { median_income: ["Low", "Medium"], tree_density: ["Low"] }') console.log(filterWithFiltersObject(data, filter1)); console.log('\nfilter2: { median_income: ["Low", "High"], tree_density: ["Low"] }') console.log(filterWithFiltersObject(data, filter2));
 .as-console-wrapper { max-height: 100%;important: top; 0; }

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

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