如何在JavaScript中从一个对象数组中获取不同的值?

842
假设我有以下内容:
var array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

什么是获取所有不同年龄的数组的最佳方法,以便得到以下结果数组的最佳方式:
[17, 35]

有没有其他方法可以更好地结构化数据,而不必迭代每个数组检查“年龄”的值,并检查其是否存在于另一个数组中,如果不存在则添加它?
如果有一种方法可以只提取不同的年龄而不用迭代...
我希望改进当前低效的方法... 如果这意味着“数组”不是对象数组,而是具有某些唯一键(即“1,2,3”)的对象“映射”,那也没关系。我只是寻找最高性能效率的方式。
以下是我目前的做法,但对我来说,迭代似乎效率很低,尽管它确实有效...
var distinct = []
for (var i = 0; i < array.length; i++)
   if (array[i].age not in distinct)
      distinct.push(array[i].age)

74
迭代不是“效率低下的”,你不能“不迭代”就对每个元素进行操作。虽然你可以使用各种看起来像函数式的方法,但最终某个层面上的东西仍需要遍历项。 - Eevee
//100% 运行代码 const listOfTags = [{ id: 1, label: "你好", color: "红色", sorting: 0 }, { id: 2, label: "世界", color: "绿色", sorting: 1 }, { id: 3, label: "你好", color: "蓝色", sorting: 4 }, { id: 4, label: "阳光", color: "黄色", sorting: 5 }, { id: 5, label: "你好", color: "红色", sorting: 6 }], keys = ['label', 'color'], filtered = listOfTags.filter( (s => o => (k => !s.has(k) && s.add(k)) (keys.map(k => o[k]).join('|')) ) (new Set) );console.log(filtered); - Sandeep Mishra
1
赏金很高,但是使用给定数据和答案的问题已经在这里回答了:https://dev59.com/TlQJ5IYBdhLWcg3wlm7B。那么赏金的目的是什么?我应该用两个或更多键来回答这个特定的问题吗? - Nina Scholz
1
Set 对象和 map 是浪费的。这个任务只需要一个简单的 .reduce() 阶段即可。 - Redu
请查看此示例,https://stackoverflow.com/a/58944998/13013258。 - Kezia Rose
/答案:/ var ListDistinct=[]; array.forEach((m)=>{ if(ListDistinct.indexOf(m.age)<0)ListDistinct.push(m.age); }); console.log(ListDistinct); - garish
65个回答

4

    var array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

    console.log(Object.keys(array.reduce((r,{age}) => (r[age]='', r) , {})))

输出:

Array ["17", "35"]

3
如果您已经使用 Array.prototype.includes 或愿意使用 polyfill ,那么这个方法可以解决问题:
var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });

3
如果你像我一样喜欢更加“实用”的方式,而不会影响速度,那么这个例子使用快速字典查找包裹在reduce闭包中。
var array = 
[
    {"name":"Joe", "age":17}, 
    {"name":"Bob", "age":17}, 
    {"name":"Carl", "age": 35}
]
var uniqueAges = array.reduce((p,c,i,a) => {
    if(!p[0][c.age]) {
        p[1].push(p[0][c.age] = c.age);
    }
    if(i<a.length-1) {
        return p
    } else {
        return p[1]
    }
}, [{},[]])

根据这个测试,我的解决方案比建议的答案快两倍。

3

这是一行简单代码,性能优秀。在我的测试中比ES6解决方案快了6%。

var ages = array.map(function(o){return o.age}).filter(function(v,i,a) {
    return a.indexOf(v)===i
});

@Jeb50,能否添加一个易于阅读的多行代码?看着这里的其他代码,我真的觉得它们不易于阅读或理解。我认为最好将其放在一个描述其功能的函数中。 - Craig
3
使用箭头函数:array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i)。我现在很少使用函数关键字,所以当我看到它时,需要读两遍才能理解。 - Drenai

3
我知道我的代码有点长且时间复杂度有点高,但它容易理解,所以我尝试了这种方法。
我正在尝试在这里开发基于原型的函数,并且代码也在更改。
这里,Distinct是我自己的原型函数。

<script>
  var array = [{
      "name": "Joe",
      "age": 17
    },
    {
      "name": "Bob",
      "age": 17
    },
    {
      "name": "Carl",
      "age": 35
    }
  ]

  Array.prototype.Distinct = () => {
    var output = [];
    for (let i = 0; i < array.length; i++) {
      let flag = true;
      for (let j = 0; j < output.length; j++) {
        if (array[i].age == output[j]) {
          flag = false;
          break;
        }
      }
      if (flag)
        output.push(array[i].age);
    }
    return output;
  }
  //Distinct is my own function
  console.log(array.Distinct());
</script>


3

const array = [{
    "name": "Joe",
    "age": 17
  },
  {
    "name": "Bob",
    "age": 17
  },
  {
    "name": "Carl",
    "age": 35
  }
]

const uniqueArrayByProperty = (array, callback) => {
  return array.reduce((prev, item) => {
    const v = callback(item);    
    if (!prev.includes(v)) prev.push(v)          
    return prev
  }, [])    
}

console.log(uniqueArrayByProperty(array, it => it.age));


2

以下代码将显示年龄的唯一数组以及不含重复年龄的新数组

var data = [
  {"name": "Joe", "age": 17}, 
  {"name": "Bob", "age": 17}, 
  {"name": "Carl", "age": 35}
];

var unique = [];
var tempArr = [];
data.forEach((value, index) => {
    if (unique.indexOf(value.age) === -1) {
        unique.push(value.age);
    } else {
        tempArr.push(index);    
    }
});
tempArr.reverse();
tempArr.forEach(ele => {
    data.splice(ele, 1);
});
console.log('Unique Ages', unique);
console.log('Unique Array', data);```

2

这里有很多很好的答案,但是没有一个回答到以下这一行:

是否有其他方式来构造数据结构?

我会创建一个对象,它的键是年龄,每个键指向一个名字数组。

var array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }];

var map = array.reduce(function(result, item) {
  result[item.age] = result[item.age] || [];
  result[item.age].push(item.name);
  return result;
}, {});

console.log(Object.keys(map));
console.log(map);

通过这种方式,您已将数据结构转换为非常容易检索不同年龄的结构。

以下是更紧凑的版本,它还存储整个对象而不仅仅是名称(如果您处理具有多于2个属性的对象,则无法将它们存储为键和值)。

var array = [{ "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 }];

var map = array.reduce((r, i) => ((r[i.age] = r[i.age] || []).push(i), r), {});

console.log(Object.keys(map));
console.log(map);


1
假设我们有以下数据:arr=[{id:1,age:17},{id:2,age:19} ...],那么我们可以这样找到唯一的对象 -
function getUniqueObjects(ObjectArray) {
    let uniqueIds = new Set();
    const list = [...new Set(ObjectArray.filter(obj => {
        if (!uniqueIds.has(obj.id)) {
            uniqueIds.add(obj.id);
            return obj;
        }
    }))];

    return list;
}

在此处查看Codepen链接


1

目前正在开发一种typescript库,以orm的方式查询js对象。您可以从下面的链接下载。本答案解释了如何使用下面的库来解决问题。

https://www.npmjs.com/package/@krishnadaspc/jsonquery?activeTab=readme

var ageArray = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

const ageArrayObj = new JSONQuery(ageArray)
console.log(ageArrayObj.distinct("age").get()) // outputs: [ { name: 'Bob', age: 17 }, { name: 'Carl', age: 35 } ]

console.log(ageArrayObj.distinct("age").fetchOnly("age")) // outputs: [ 17, 35 ]

Runkit实时链接:https://runkit.com/pckrishnadas88/639b5b3f8ef36f0008b17512

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接