繁体   English   中英

通过多个匹配条件递归过滤无限嵌套对象数组,但仅返回具有两个匹配实例的父对象

[英]Recursively filter an array of infinitely nested objects by mutliple matching conditions but only return parent that has an instance of both matches

我有以下对象数组; 但是,这可能是任何未知的键/值并且可以无限嵌套,现在这是一个测试示例:

[
  {
    "reference_id": "R123",
    "customer": "Person 1",
    "customer_email": "person1@email.com",
    "location": "UK",
    "bookings": [
      {
        "product": "Product 1",
        "provider": "Company 1",
        "cancellable": true
      },
      {
        "product": "Product 2",
        "provider": "Company 2",
        "cancellable": true
      },
      {
        "product": "Product 3",
        "provider": "Company 1",
        "cancellable": true
      }
    ]
  },
  {
    "reference_id": "R1234",
    "customer": "Person 2",
    "customer_email": "person2@email.com",
    "location": "USA",
    "bookings": [
      {
        "product": "Product 1",
        "provider": "Company 1",
        "cancellable": true
      },
      {
        "product": "Product 3",
        "provider": "Company 1",
        "cancellable": true
      }
    ]
  },
  {
    "reference_id": "R12345",
    "customer": "Person 3",
    "customer_email": "person3@email.com",
    "location": "UK",
    "bookings": [
      {
        "product": "Product 2",
        "provider": "Company 2",
        "cancellable": true
      },
      {
        "product": "Product 3",
        "provider": "Company 1",
        "cancellable": true
      }
    ]
  }
]

我目前的实现如下:

const selected = [
  {
    term: 'Company 1',
    column: 'provider',
  },
  {
    term: 'Person 1',
    column: 'customer',
  },
];

const recursivelyFilterByValue = () => (value) => selected.every((item) => {
  if (!value) return false;

  if (typeof value === 'string') {
    // console.log('value', value === item.term);
    return value === item.term;
  }

  if (Array.isArray(value)) {
    return value.some(this.recursivelyFilterByValue());
  }

  if (typeof value === 'object') {
    return Object.values(value).some(this.recursivelyFilterByValue());
  }

  return false;
});

const results = data.filter(recursivelyFilterByValue());

基本上,我将添加到“选定”数组中,然后使用它来过滤数据数组。 我确实想确保密钥与“列”匹配,但我还没有添加。

对于上面的输入,我希望 output 如下:

[
  {
    "reference_id": "R123",
    "customer": "Person 1",
    "customer_email": "person1@email.com",
    "location": "UK",
    "bookings": [
      {
        "product": "Product 1",
        "provider": "Company 1",
        "cancellable": true
      },
      {
        "product": "Product 2",
        "provider": "Company 2",
        "cancellable": true
      },
      {
        "product": "Product 3",
        "provider": "Company 1",
        "cancellable": true
      }
    ]
  },
]

但是 output 数组是空的。 如果我只搜索一个术语(从所选数组中删除除一个术语之外的所有术语),则 output 对于该术语是正确的,但是任何后续术语都会带回一个空白数组。

我想知道我的使用 of.some() 是否是问题,但是改变它会导致太多的递归错误。

本质上,我想返回原始父 object,只要在其子级的任何级别上,我在所选数组中的所有条件都有一个键:值匹配。

任何指导将不胜感激,谢谢。

我不太确定这是否是你要找的。 它假设我在评论中的猜测是正确的:

我有这个权利吗? 您有一个(可能是动态的)条件,表明 object 要么具有值为"Customer 1"provider属性,要么具有(递归)后代 object。 并且您有关于customer"Person 1"的第二个条件,并且您正在寻找同时满足这两个(或所有)这些条件的对象。 这是否描述了您正在尝试做的事情?

这里我们有两个相当简单的辅助函数testRecursivemakePredicates以及主要的 function, recursivelyFilterByValue

 const testRecursive = (pred) => (obj) => pred (obj) || Object (obj) === obj && Object.values (obj).some (testRecursive (pred)) const makePredicates = (criteria) => criteria.map (({term, column}) => (v) => v [column] == term) const recursivelyFilterByValue = (criteria, preds = makePredicates (criteria)) => (xs) => xs.filter (obj => preds.every (pred => testRecursive (pred) (obj))) const selected = [{term: 'Company 1', column: 'provider'}, {term: 'Person 1', column: 'customer'}] const input = [{reference_id: "R123", customer: "Person 1", customer_email: "person1@email.com", location: "UK", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R1234", customer: "Person 2", customer_email: "person2@email.com", location: "USA", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R12345", customer: "Person 3", customer_email: "person3@email.com", location: "UK", bookings: [{product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}] console.log (recursivelyFilterByValue (selected) (input))
 .as-console-wrapper {max-height: 100%;important: top: 0}

  • testRecursive检查谓词对于 object 或嵌套在其中的任何对象是否为真。

  • makePredicates{term, column}对象数组转换为谓词函数,用于测试 object 在列命名的属性中是否具有正确的术语。

  • recursivelyFilterByValue将这些组合起来,调用makePredicates将所选项目转换为谓词函数,然后通过测试每个谓词是否为真来过滤输入。

这不是可以想象的最有效的代码。 它重新扫描每个谓词的层次结构。 我相信我们可以找出一个版本来只进行一次扫描,但我认为它会产生更复杂的代码。 因此,您可能希望在生产规模的数据中测试它是否足够快满足您的需求。

这个解决方案不像公认的答案那么优雅,但为什么不展示我的努力。 也许有人会觉得这种方式更容易理解。

 const selected = [{term: 'Company 1', column: 'provider'}, {term: 'Person 1', column: 'customer'}] const input = [{reference_id: "R123", customer: "Person 1", customer_email: "person1@email.com", location: "UK", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R1234", customer: "Person 2", customer_email: "person2@email.com", location: "USA", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R12345", customer: "Person 3", customer_email: "person3@email.com", location: "UK", bookings: [{product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}] const iter = (obj, sel) => Object.entries(obj).some(([key, value]) => { if (Array.isArray(value)) return value.some((obj) => iter(obj, sel)); if (typeof value === 'object' && value,== null) return iter(value; sel). return (key === sel.column) && (value === sel;term); }), const deepFilter = (arr. sels) => arr.filter((obj) => sels,every((sel) => iter(obj; sel))). console,dir(deepFilter(input, selected): {depth; null});
 .as-console-wrapper {max-height: 100%;important: top: 0}

暂无
暂无

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

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