【问题标题】:Filter all values in array of objects过滤对象数组中的所有值
【发布时间】:2020-05-14 10:59:21
【问题描述】:

假设我们有以下数组:

const arr = [{
    id: 0,
    title: 'C',
    countries: [{
      val: "1173",
      label: "Nice"
    }, {
      val: "1172",
      label: "(Yeah)"
    }],
    companies: [{
      val: "7346",
      label: "Hello World"
    }]
  },
  {
    id: 1,
    title: 'B',
    countries: [{
      val: "1175",
      label: "Like it"
    }],
    companies: [{
      val: "8294",
      label: "Javascript"
    }]
  },
]

我想搜索此数组中的所有值。

这是我的方法:

const objFields = ['countries', 'companies'];
const filterBySearchTerm = (arr, filters) => {
  if (!(arr && arr.length)) {
    return [];
  }

  // filters looks like this: {search: 'hello'}

  const sT = filters.search;
  const searchTermVariations = [sT.toLowerCase()];
  console.log(searchTermVariations);

  /* Start transform all values to arrays */
  const clonedArr = [...arr];
  clonedArr.forEach((job) => {
    const objKeys = Object.keys(job);
    objKeys.forEach((key) => {
      const currVal = job[key];
      const currValToUse = Array.isArray(currVal) ? currVal : [currVal];
      // eslint-disable-next-line no-param-reassign
      job[key] = [...currValToUse];
    });
  });
  /* End transform all values to arrays */

  /* Start transform all obj-values to plain strings */
  const results = clonedArr.filter((itm) => {
    const vals = Object.keys(itm).filter((el) => objFields.includes(el));
    vals.forEach((key) => {
      // eslint-disable-next-line no-param-reassign
      itm[key] = itm[key].map((el) => [el.label, el.val]);
    });

    return vals;
  });

  /* End transform all obj-values to plain strings */

  // perform filtering
  console.info('!! results:', results);
  return results;
};

我想说的是,我现在觉得我的方法太丑陋了。您知道如何更短、更智能地完成这项工作吗?

【问题讨论】:

  • 你想要的输出是什么?
  • 我可能在stackoverflow.com/questions/61538865/…之前回答过类似的问题
  • @Yousaf 例如,如果输入“yeah”或“hello”或“world”,则数组中的第一个对象应在过滤后保留在数组中。所以是全文搜索。
  • @A.L 是的,但我的价值观结构更深,我有不同的结构深度。每个对象中的所有值都应与 searchTerm 匹配。

标签: javascript arrays filter


【解决方案1】:

如果您想通过任何属性值过滤对象数组,使用子字符串匹配、不区分大小写并递归到数组中,这样做:

// Checks to see if any object property matches the search value
// (which must be in lower case), or if any of its array properties
// contains an object that matches
function matchesAnyPropValue(obj, search) {
    return Object.values(obj).some(value =>
        Array.isArray(value)
        ? value.some(v => matchesAnyPropValue(v, search))
        : String(value).toLocaleLowerCase().includes(search)
    );
}

// Apply the given filter to the given array    
function applySearch(arr, filters) {
    const search = filters.search.toLocaleLowerCase();
    return arr.filter(entry => matchesAnyPropValue(entry, search));
}

现场示例:

const arr = [{
    id: 0,
    title: 'C',
    countries: [{
      val: "1173",
      label: "Nice"
    }, {
      val: "1172",
      label: "Yeah"
    }],
    companies: [{
      val: "7346",
      label: "Hello World"
    }]
  },
  {
    id: 1,
    title: 'B',
    countries: [{
      val: "1175",
      label: "Like it"
    }],
    companies: [{
      val: "8294",
      label: "Javascript"
    }]
  },
];

function matchesAnyPropValue(obj, search) {
    return Object.values(obj).some(value =>
        Array.isArray(value)
        ? value.some(v => matchesAnyPropValue(v, search))
        : String(value).toLocaleLowerCase().includes(search)
    );
}

function applySearch(arr, filters) {
    const search = filters.search.toLocaleLowerCase();
    return arr.filter(entry => matchesAnyPropValue(entry, search));
}

document.getElementById("search").addEventListener("click", () => {
    const filters = {search: document.getElementById("filter").value};
    const filtered = applySearch(arr, filters);
    console.clear();
    console.log(filtered);
});
.as-console-wrapper {
    max-height: 100% !important;
}
<input type="text" id="filter" value="yeah">
<input type="button" id="search" value="Search">

【讨论】:

  • 非常感谢。很好的解决方案。这就是我一直在寻找的。​​span>
猜你喜欢
  • 2017-02-10
  • 2018-07-16
  • 2016-02-14
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-17
  • 1970-01-01
相关资源
最近更新 更多