使用 Ramda 基于多个条件过滤列表

Filter list based on multiple criteria with Ramda

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

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 不是正确的方法?

R.where 需要一个对象,其中包含您希望测试的每个 属性 的谓词函数。要通过测试对象需要满足所有谓词(和)。

要测试当前对象的 make 让我们说“audi` 针对选项数组 (or),您可以使用 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>