用JavaScript按属性过滤对象数组

huangapple go评论79阅读模式
英文:

Filter an array of objects by property JavaScript

问题

vehicles = [
{ "name": "Ford", "type": "SUV", "brand": "Explorer" },
{ "name": "Ford", "type": "SUV", "brand": "Explorer" },
{ "name": "Ford", "type": "truck", "brand": "F-150" },
{ "name": "Chrysler", "type": "car", "brand": "Sierra" },
{ "name": "GM", "type": "truck", "brand": "Sierra" },
{ "name": "GM", "type": "truck", "brand": "Sierra" },
]

如何按对象的两个属性筛选,使得只剩下每组中的一个?比如说name和brand必须相同。

vehicles = [
{ "name": "Ford", "type": "SUV", "brand": "Explorer" },
{ "name": "Ford", "type": "truck", "brand": "F-150" },
{ "name": "Chrysler", "type": "car", "brand": "Sierra" },
{ "name": "GM", "type": "truck", "brand": "Sierra" },
]

这段代码不起作用:

const filteredVehicles = vehicles.filter((item) => item.name === name & item.brand === brand );

英文:

I have an array of objects.

vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
]

How do I filter this by two properties of the objects so there is only one of each? Say name and brand have to be the same?

vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
]

This isn't working:

const filteredVehicles = vehicles.filter((item) => item.name === name & item.brand === brand );

答案1

得分: 1

有一些库可以帮助实现这个功能,但使用原生 JavaScript,使用过滤器(filter)应该可以。在下面的示例中,filter 用于返回那些数组中后面没有不匹配的元素的元素。

const vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
];

const reduced = vehicles.filter((el, i, ary) => !ary.slice(i + 1)
  .some(x => x.name === el.name && x.brand === el.brand));
console.log(reduced);

请随意更改 some 内部的表达式以仅匹配品牌。

英文:

There are libraries that could help with this, but to do it with vanilla JavaScript, filter should be fine. In the example below filter is used to return elements where there are no elements later in the array that don't match.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const vehicles = [
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;F-150&quot; },
  { &quot;name&quot;: &quot;Chrysler&quot;, &quot;type&quot;: &quot;car&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
];

const reduced = vehicles.filter((el, i, ary) =&gt; !ary.slice(i + 1)
  .some(x =&gt; x.name === el.name &amp;&amp; x.brand === el.brand));
console.log(reduced);

<!-- end snippet -->

Feel free to change the expression inside of some to match by just the brand.

答案2

得分: 0

使用reduce和Object.values生成一个唯一的键,可以根据所有属性进行过滤。

const vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
];

const deduped = Object.values(vehicles.reduce((o, v) => {
  o[Object.values(v).join("-")] = v;
  return o;
}, {}));

console.log(deduped);

如果只想根据特定属性进行过滤:

const vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
];

const deduped = Object.values(vehicles.reduce((o, v) => {
  o[`${v.name}-${v.brand}`] = v;
  return o;
}, {}));

console.log(deduped);

如果要动态选择属性进行过滤:

const vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
];

const filterOn = ['name', 'brand'];

const deduped = Object.values(vehicles.reduce((o, v) => {
  key = filterOn.map(p => v[p]).join("-");
  o[key] = v; // 保留最后一个遇到的
  // o[key] = o[key] || v;  // 保留第一个遇到的
  return o;
}, {}));

console.log(deduped);
英文:

Using reduce and Object.values to generate a unique key can filter on all the properties.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const vehicles = [
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;F-150&quot; },
  { &quot;name&quot;: &quot;Chrysler&quot;, &quot;type&quot;: &quot;car&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
];

const deduped = Object.values(vehicles.reduce((o, v) =&gt; {
  o[Object.values(v).join(&quot;-&quot;)] = v;
  return o;
}, {}));

console.log(deduped);

<!-- end snippet -->

If you only want to filter on specific ones

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const vehicles = [
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;F-150&quot; },
  { &quot;name&quot;: &quot;Chrysler&quot;, &quot;type&quot;: &quot;car&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
];

const deduped = Object.values(vehicles.reduce((o, v) =&gt; {
  o[`${v.name}-${v.brand}`] = v;
  return o;
}, {}));

console.log(deduped);

<!-- end snippet -->

If you want to be dynamic with the properties

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const vehicles = [
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
  { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;F-150&quot; },
  { &quot;name&quot;: &quot;Chrysler&quot;, &quot;type&quot;: &quot;car&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
  { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
];

const filterOn = [&#39;name&#39;, &#39;brand&#39;];

const deduped = Object.values(vehicles.reduce((o, v) =&gt; {
  key = filterOn.map(p =&gt; v

).join(&quot;-&quot;); o[key] = v; // keeps the last one encountered // o[key] = o[key] || v; // keep just the first one encountered return o; }, {})); console.log(deduped);

<!-- end snippet -->

答案3

得分: -1

这是一个通用的函数,你可以提供一个props数组给它。它通过使用与每个属性对应的Set来跟踪相同的属性,这意味着它的运行时间为O(nm),其中n是数组的长度,m是要检查的属性数。

function filterByProps(arr, props) {
    const sets = props.map((prop) => [prop, new Set()])

    return arr.filter((item) => {
        let numSameProps = 0

        for (const [prop, set] of sets) {
            if (set.has(item[prop])) {
                ++numSameProps
            } else {
                set.add(item[prop])
            }
        }

        return numSameProps < props.length
    })
}

const vehicles = [
    { "name": "Ford", "type": "SUV", "brand": "Explorer" },
    { "name": "Ford", "type": "SUV", "brand": "Explorer" },
    { "name": "Ford", "type": "truck", "brand": "F-150" },
    { "name": "Chrysler", "type": "car", "brand": "Sierra" },
    { "name": "GM", "type": "truck", "brand": "Sierra" },
    { "name": "GM", "type": "truck", "brand": "Sierra" },
]

for (const propList of [['brand'], ['name', 'brand'], ['name', 'brand', 'type']]) {
    const results = filterByProps(vehicles, propList)
    console.log(new Intl.ListFormat('en-US').format(propList))
    console.log('length', results.length)
    console.log(results)
}

请注意,这是你提供的代码的翻译部分。

英文:

Here's a generic function that you can supply an array of props to. It keeps track of the same props by using a Set corresponding to each property, meaning it runs in O(nm) time, where n is the length of the array and m is the number of properties checked.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function filterByProps(arr, props) {
    const sets = props.map((prop) =&gt; [prop, new Set()])

    return arr.filter((item) =&gt; {
        let numSameProps = 0

        for (const [prop, set] of sets) {
            if (set.has(item[prop])) {
                ++numSameProps
            } else {
                set.add(item[prop])
            }
        }

        return numSameProps &lt; props.length
    })
}

const vehicles = [
    { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
    { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;SUV&quot;, &quot;brand&quot;: &quot;Explorer&quot; },
    { &quot;name&quot;: &quot;Ford&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;F-150&quot; },
    { &quot;name&quot;: &quot;Chrysler&quot;, &quot;type&quot;: &quot;car&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
    { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
    { &quot;name&quot;: &quot;GM&quot;, &quot;type&quot;: &quot;truck&quot;, &quot;brand&quot;: &quot;Sierra&quot; },
]

for (const propList of [[&#39;brand&#39;], [&#39;name&#39;, &#39;brand&#39;], [&#39;name&#39;, &#39;brand&#39;, &#39;type&#39;]]) {
    const results = filterByProps(vehicles, propList)
    console.log(new Intl.ListFormat(&#39;en-US&#39;).format(propList))
    console.log(&#39;length&#39;, results.length)
    console.log(results)
}

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年7月14日 09:06:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76684115.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定