如何使用Lodash过滤多个潜在属性的对象集合?

时间:2018-03-07 17:25:11

标签: javascript lodash

我正在建立一个简单的过滤用户界面。我想使用逻辑AND过滤对象集合,其中对象的匹配取决于任意一组键中每个对象的多个潜在值。要过滤的对象如下所示:

collection = [
  {
    'Kind': 'Instrument',
    'Color': 'Orange',
    'Shape': 'Square',
    'Name': 'Foobar',
  },
  ...
]

用户的点击式过滤结果如下所示:

filter = {
  'Color': ['Red', 'Orange', 'Yellow'],
  'Shape': ['Circle']
}

在这种情况下,我想将集合过滤到以下所有对象:

  • 颜色为红色或橙色或黄色
  • AND Shape is Circle

filter对象有任意数量的键,所以我不能轻松编写这样的手动过滤器函数:

results = _.filter(collection, item => {
  return _.includes(['Red', 'Orange', 'Yellow'], item['Color']) && _.includes(['Circle'], item['Shape'])
})

使用Lodash实现这一目标的最简洁方法是什么?对于filtercollection内的每个项目,我是否需要遍历_.filter中的每个密钥?还是有更好的方式?

P.S。我没有正确的语言来谈论我正在尝试做的事情。描述这个问题的最佳关键词是什么?

4 个答案:

答案 0 :(得分:1)

你非常接近:



const collection = [
  // Won't be in the output.
  {
    'Kind': 'Instrument',
    'Color': 'Orange',
    'Shape': 'Square',
    'Name': 'Foobar',
  },
  // Will be in the output.
  {
    'Kind': 'Instrument',
    'Color': 'Orange',
    'Shape': 'Circle',
    'Name': 'Foobar',
  },
  // Won't be in the output.
  {
    'Kind': 'Derp',
    'Color': 'NoWorky',
    'Shape': 'HAHAHAHA',
    'Name': 'uWin',
  }
];

const filter = {
  'Color': ['Red', 'Orange', 'Yellow'],
  'Shape': ['Circle']
};

const results = _.filter(collection, (item) => {
  return _.chain(filter)
    .keys()
    .reduce((currentBoolean, next) => {
      console.log(currentBoolean, next, filter[next], item[next]);
      return _.isNil(item[next]) ? currentBoolean : _.includes(filter[next], item[next]) && currentBoolean;
    }, true)
    .value();
  
  // This doesn't work because you're trying to do arbitrary keys.
  // return _.includes(filter.Color, item.Color) && _.includes(filter.Shape, item.Shape));
});

console.log(results);

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

应用一些功能风格,我只是在你说的时候做。希望代码足够解释,否则请告诉我,我会尝试澄清事情(尽管我认为你没有使用它,但lodashfp会更清晰一些)。

希望它有所帮助。

const isValIncluded = item => (value, key) => _.includes(value, _.get(item, key, null));
const isValid = filters => item => _.every(filters, isValIncluded(item));
const filterCol = coll => filters => _.filter(coll, isValid(filters));

const collection = [{
    'Kind': 'Instrument',
    'Color': 'Orange',
    'Shape': 'Square',
    'Name': 'Foobar',
  },
  {
    'Kind': 'Instrument',
    'Color': 'Orange',
    'Shape': 'Circle',
    'Name': 'Foobar',
  },
  {
    'Kind': 'XXX',
    'Color': 'YYY',
    'Shape': 'ZZZ',
    'Name': 'FFF',
  },
  {
    'Kind': 'Instrument',
    'Color': 'Red',
    'Shape': 'Circle',
    'Name': 'Foobar',
  }
];

const filters = {
  'Color': ['Red', 'Orange', 'Yellow'],
  'Shape': ['Circle']
};

console.log(filterCol(collection)(filters));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>

答案 2 :(得分:0)

您可以简化使用

results = _.filter(collection, item => item.Shape==='Circle' && _.includes(['Red', 'Orange', 'Yellow'], item.Color));

通过在此处以不同方式命名filter对象来避免混淆可能是一个好主意。

答案 3 :(得分:0)

这将适用于要过滤给定属性的项目列表,该属性是“ doorColour”之类的字符串,还是表示给定属性路径的字符串数组,例如[“ town”,“ street”,“ doorColour” ']表示嵌套在项上的值为town.street.doorColour。

它还可以过滤多个值,因此您只需要传入表示要保留的字符串值的子字符串数组即可,它将保留具有字符串值的项目,该字符串值包含在substrings数组中的任何子字符串。

如果将其设置为false,则最终参数'includes'可确保保留这些值,它将排除这些值并保留不具有您在子字符串数组中指定的任何值的

import { flatMap, path } from 'lodash/fp';

const filteredListForItemsIncludingSubstringsOnAGivenProperty = (items, givenProperty, substrings, including=true) => flatMap((item) =>
substrings.find((substring) => path(givenProperty)(item) && path(givenProperty)(item).includes(substring))
  ? including
    ? [item]
    : []
  : including
  ? []
  : [item])(items);