javascript - 根据嵌套对象数组中的动态键过滤数组

标签 javascript arrays object filter ecmascript-6

我有一个包含嵌套对象的数组。像这样:

const results = [
    { 
        general: {
            orderID: '5567',
            created: 1548765626101,
            status: 'new'
        },

        company: {
            companyName: 'company x',
            companyEmail: 'info@companyx.com',
            companyContact: 'John Doe'
        },

        customer: {
            customerName: 'Jane Doe',
            customerEmail: 'janedoe@email.com'
        },

        products: [
            {
                productID: 4765756,
                productName: 'Product x',
                productDescription: 'Description for product x'
            },
            {
                productID: 4767839,
                productName: 'Product y',
                productDescription: 'Description for product y'
            }
        ],

        payment: {
            price: 1000,
            method: 'cash'
        }

    },
]

(为了让它有点结构化,我只为这个问题插入了一个结果对象。但假设结果数组中有 100 个元素。)

用户可以输入搜索词并选中/取消选中将包含或排除这些键的键。键被硬编码在列表中。

举个例子。用户键入“jane”并检查 customerName 和 customerEmail 作为要搜索的关键字。或者用户输入“x”并检查产品名称。

如何动态搜索这些选中的键?我已经将选定的键放入数组中。

所以对于第一个示例,我有 ['customerName', 'customerEmail']

第二个是 ['productName']

我之前对硬编码键使用过 array.filter() 但我不知道如何过滤这些动态键。

谁能帮我分解一下不同的步骤?我正在使用 es6,没有外部库。

最佳答案

您需要遍历 results 数组,然后深入搜索每个对象以找到匹配项。为此你需要

  • 获取所有键/值对
  • 如果值为对象,则进行更深入的搜索
  • 如果值是数组,则更深入地搜索每个项目
  • 否则(值为字符串或数字)
    • 如果关键字在要搜索的字段列表中
    • 如果值与查询匹配则返回 true
    • 否则返回false

类似的东西

const deepSearcher = (fields, query) =>
  function matcher(object) {
    const keys = Object.keys(object);

    return keys.some(key => {
      const value = object[key];
      // handle sub arrays
      if (Array.isArray(value)) return value.some(matcher);
      // handle sub objects
      if (value instanceof Object) return matcher(value);
      // handle testable values
      if (fields.includes(key)) {
        // handle strings
        if (typeof value === "string") return value.includes(query);
        // handle numbers
        return value.toString() === query.toString();
      }
      return false;
    });
  };

此函数创建一个与 .filter 方法一起使用的匹配器。

const customerFilter = deepSearcher(['customerName', 'customerEmail'], 'jane')
const found = results.filter(customerFilter);

或者您可以将其直接传递给 .filter

const found = results.filter(deepSearcher(['customerName', 'customerEmail'], 'jane'));

您传递给 deepSearcher 的字段不必属于同一个对象。匹配器将测试任何匹配项(但它们必须指向字符串/数字才能使此代码正常工作)。


工作测试用例

const results = [{
  general: {
    orderID: "5567",
    created: 1548765626101,
    status: "new"
  },
  company: {
    companyName: "company x",
    companyEmail: "info@companyx.com",
    companyContact: "John Doe"
  },
  customer: {
    customerName: "Jane Doe",
    customerEmail: "janedoe@email.com"
  },
  products: [{
      productID: 4765756,
      productName: "Product x",
      productDescription: "Description for product x"
    },
    {
      productID: 4767839,
      productName: "Product y",
      productDescription: "Description for product y"
    }
  ],
  payment: {
    price: 1000,
    method: "cash"
  }
}];

const deepSearcher = (fields, query) =>
  function matcher(object) {
    const keys = Object.keys(object);

    return keys.some(key => {
      const value = object[key];
      // handle sub arrays
      if (Array.isArray(value)) return value.some(matcher);
      // handle sub objects
      if (value instanceof Object) return matcher(value);
      // handle testable values
      if (fields.includes(key)) {
        // handle strings
        if (typeof value === "string") return value.includes(query);
        // handle numbers
        return value.toString() === query.toString();
      }
      return false;
    });
  };

const matchingCustomer = results.filter(deepSearcher(["customerName", "customerEmail"], 'jane'));
console.log('results with matching customer:', matchingCustomer.length);

const matchingProduct = results.filter(deepSearcher(["productName"], 'x'));
console.log('results with matching product:', matchingProduct.length);


const matchingPrice = results.filter(deepSearcher(["price"], '1000'));
console.log('results with matching price:', matchingPrice.length);

const nonMatchingPrice = results.filter(deepSearcher(["price"], '500'));
console.log('results with non matching price:', nonMatchingPrice.length);

关于javascript - 根据嵌套对象数组中的动态键过滤数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54713462/

相关文章:

javascript - javascript 迭代对象元素

javascript - 如何在javascript中对键/值对象进行排序?

python - numpy 中的索引(与 max/argmax 相关)

javascript - 将对象添加到数组

javascript - react JSX : Access props keys dynamically

javascript - 访问 .val()、.text() 等中元素的值,无需双重选择或缓存

javascript - javascript 中的字符串搜索无法找到当前字符串

javascript - 正确更新状态数组中给定索引处的项目

javascript - 在html中显示来自javascript数组的图像

Python 的新型类的基础—— `object` 和 `type`