使用 Ramda 根据多个条件过滤列表

时间:2021-04-21 00:38:31

标签: javascript arrays filtering ramda.js

我有一个汽车列表,我想根据过滤器对象(汽车)对其进行过滤:

const cars = [
    {original: {"make": "audi", "model": "a4"}},
    {original: {"make": "bmw", "model": "m5"}},
    {original: {"make": "mercedes", "model": "s"}},
    {original: {"make": "audi", "model": "a6"}},
];

过滤器对象,对于同一属性可以有多个条件(这些应被视为OR 过滤器)。该词典中的每个条目(“make”、“model”)都应被视为一个 AND 过滤器。

const filterObject = {
    "make": {
        filters: [
            {prop: "make", value: "audi"},
            {prop: "make", value: "bmw"}
        ]
    }, 
    "model": {
        filters: [
            {prop: "model", value: "a6"}
        ]
    }
}

所以在这种情况下,我应该取回 audi - a6。 使用 ramda 我可以做到这一步:

filter(
  where({
      make: equals("audi"),
      model: equals("a6")
  }), 
  map(x => x.original, data)
)

哪个有效,但有几个问题:

  1. filterObject 是动态组装的,所以我事先不知道过滤了哪些属性。我应该以某种方式将对象映射到 where 内,但是我遇到了多个条件标准。如何让 where 了解每个属性的多个谓词?
  2. 最后我应该取回原始(过滤后的)数组。但是相关部分隐藏在属性 (original) 中,所以在我开始过滤之前,我映射数组以将相关部分提供给 where 函数,因此最终这个映射数组是返回。

也许 where 不是正确的方法?

1 个答案:

答案 0 :(得分:2)

R.where 需要一个对象,该对象具有您要测试的每个属性的谓词函数。通过测试对象需要满足所有谓词(和)。

要测试当前对象的 make,让我们说“audi` 对一组选项(或),您可以使用 R.includes。

所以第一步是创建一个 where 对象,其中每个谓词都根据一组值检查当前对象的值。

const { map, pipe, prop, pluck, includes, flip, where } = R;

const createFilters = map(pipe(
  prop('filters'),
  pluck('value'),
  flip(includes)
));

const cars = [{"original":{"make":"audi","model":"a4"}},{"original":{"make":"bmw","model":"m5"}},{"original":{"make":"mercedes","model":"s"}},{"original":{"make":"audi","model":"a6"}}];

const filterObject = {"make":{"filters":[{"prop":"make","value":"audi"},{"prop":"make","value":"bmw"}]},"model":{"filters":[{"prop":"model","value":"a6"}]}};

const filters = createFilters(filterObject);

console.log(filters);

console.log(where(filters, {"make":"audi","model":"a4"})) // false
console.log(where(filters, {"make":"audi","model":"a6"})) // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

然后您在过滤数据时,从 origin 中获取对象,并将 R.where 与应用的过滤器一起使用:

const { map, pipe, prop, pluck, includes, flip, curry, filter, where } = R;

const createFilters = map(pipe(
  prop('filters'),
  pluck('value'),
  flip(includes)
));

const fn = curry((filters, data) => filter(pipe(
  prop('original'),
  where(createFilters(filters)), 
))(data));

const cars = [{"original":{"make":"audi","model":"a4"}},{"original":{"make":"bmw","model":"m5"}},{"original":{"make":"mercedes","model":"s"}},{"original":{"make":"audi","model":"a6"}}];

const filterObject = {"make":{"filters":[{"prop":"make","value":"audi"},{"prop":"make","value":"bmw"}]},"model":{"filters":[{"prop":"model","value":"a6"}]}};

const result = fn(filterObject)(cars);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>