从对象数组中提取属性值作为数组

内容来源于 Stack Overflow,遵循 CC BY-SA 4.0 许可协议进行翻译与使用。IT领域专用引擎提供翻译支持

腾讯云小微IT领域专用引擎提供翻译支持

原文
Stack Overflow用户 修改于2019-03-21
  • 该问题已被编辑
  • 提问者: Stack Overflow用户
  • 提问时间: 2013-10-25 21:13

我有一个具有以下结构的JavaScript对象数组:

objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

我想从每个对象中提取一个字段,并获得一个包含这些值的数组,例如,字段 foo 将提供数组 [ 1, 3, 5 ]

我可以用这个简单的方法做到这一点:

function getFields(input, field) {
    var output = [];
    for (var i=0; i < input.length ; ++i)
        output.push(input[i][field]);
    return output;
var result = getFields(objArray, "foo"); // returns [ 1, 3, 5 ]

有没有一种更优雅或更惯用的方式来做这件事,这样就不需要定制实用函数了?

关于 suggested duplicate 的说明,它涵盖了如何将单个对象转换为数组。

浏览 1664 关注 0 得票数 1487
  • 得票数为Stack Overflow原文数据
原文
操作
修改于2019-06-15
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2013-10-25 21:14
得票数 680

是的,但它依赖于JavaScript的ES5特性。这意味着它不能在IE8或更早的版本中工作。

var result = objArray.map(function(a) {return a.foo;});

在ES6兼容的JS解释器上,为了简洁起见,可以使用:

var result = objArray.map(a => a.foo);

Array.prototype.map documentation

Stack Overflow用户
回答于2013-10-25
得票数 18

使用 Array.prototype.map

function getFields(input, field) {
    return input.map(function(o) {
        return o[field];
}

有关ES5之前版本的浏览器的填充程序,请参阅上面的链接。

修改于2021-07-05
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2013-10-25 21:54
得票数 6

这取决于你对“更好”的定义。

其他答案指出了map的使用,这是自然的(特别是对于习惯于函数式风格的人)和简洁。我强烈建议您使用它(如果您不想为少数IE8- it人员所困扰)。因此,如果“更好”意味着“更简洁”、“可维护”、“可理解”,那么是的,它就更好了。

另一方面,这种美丽并不是没有额外的成本就能实现的。我不是microbench的狂热粉丝,但我放了一个小的 test here 。结果是可以预测的,旧的丑陋的方法似乎比map函数更快。因此,如果“更好”意味着“更快”,那么不,继续沿用传统的时尚。

同样,这只是一个微型工作台,并不是反对使用 map ,这只是我的两点意见:)。

修改于2015-11-29
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2015-11-28 16:32
得票数 2

在处理对象数组时,函数映射是一个很好的选择。尽管已经发布了一些很好的答案,但结合使用map和filter的示例可能会有所帮助。

如果要排除值未定义的属性或仅排除特定属性,可以执行以下操作:

    var obj = {value1: "val1", value2: "val2", Ndb_No: "testing", myVal: undefined};
    var keysFiltered = Object.keys(obj).filter(function(item){return !(item == "Ndb_No" || obj[item] == undefined)});
    var valuesFiltered = keysFiltered.map(function(item) {return obj[item]});

https://jsfiddle.net/ohea7mgk/

操作
修改于2019-06-15
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2016-02-09 12:00
得票数 23

最好使用某种类型的库来实现跨浏览器的保证。

在Lodash中,您可以通过以下方法获取数组中属性的值

_.map(objArray,"foo")

在下划线中

_.pluck(objArray,"foo")

两个都会回来

[1, 2, 3]
操作
回答于2016-11-19
得票数 8

虽然 map 是从对象列表中选择“列”的合适解决方案,但它也有缺点。如果不显式检查列是否存在,它将抛出一个错误,并(充其量)为您提供 undefined 。我会选择 reduce 解决方案,它可以简单地忽略该属性,甚至为您设置一个默认值。

function getFields(list, field) {
    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  check if the item is actually an object and does contain the field
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin example

即使所提供的列表中的某一项不是对象或不包含该字段,也可以这样做。

它甚至可以通过协商一个默认值来使其更加灵活,该默认值应该不是一个对象或不包含该字段。

function getFields(list, field, otherwise) {
    //  reduce the provided list to an array containing either the requested field or the alternative value
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);
        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin example

这与map相同,因为返回的数组的长度与提供的数组的长度相同。(在这种情况下, map reduce 稍微便宜一点):

function getFields(list, field, otherwise) {
    //  map the provided list to an array containing either the requested field or the alternative value
    return list.map(function(item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        return typeof item === 'object' && field in item ? item[field] : otherwise;
    }, []);
}

jsbin example

然后是最灵活的解决方案,它允许您简单地通过提供一个替代值在这两种行为之间切换。

function getFields(list, field, otherwise) {
    //  determine once whether or not to use the 'otherwise'
    var alt = typeof otherwise !== 'undefined';
    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        else if (alt) {
            carry.push(otherwise);
        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin example

由于上面的例子(希望)阐明了它的工作方式,让我们通过利用 Array.concat 函数来缩短该函数。

function getFields(list, field, otherwise) {
    var alt = typeof otherwise !== 'undefined';
    return list.reduce(function(carry, item) {
        return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
    }, []);
}

jsbin example

修改于2020-04-19
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2017-10-12 01:33
得票数 2049

这里有一个更简单的方法来实现它:

let result = objArray.map(a => a.foo);

let result = objArray.map(({ foo }) => foo)

您还可以查看 Array.prototype.map()

修改于2018-04-07
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2018-04-06 22:16
得票数 7

如果还希望支持类似数组的对象,请使用 Array.from (ES2015):

Array.from(arrayLike, x => x.foo);

与Array.prototype.map()方法相比,它的优点是输入也可以是一个集合

let arrayLike = new Set([{foo: 1}, {foo: 2}, {foo: 3}]);
修改于2018-08-23
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2018-07-11 01:36
得票数 15

在ES6中,您可以执行以下操作:

const objArray = [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
objArray.map(({ foo }) => foo)
回答于2019-04-27
得票数 7

如果您想在ES6+中使用多个值,则可以使用以下方法

objArray = [ { foo: 1, bar: 2, baz: 9}, { foo: 3, bar: 4, baz: 10}, { foo: 5, bar: 6, baz: 20} ];
let result = objArray.map(({ foo, baz }) => ({ foo, baz }))

这是因为左侧的 {foo, baz} 使用的是 object destructoring ,而右侧的箭头由于使用了 ES6's enhanced object literals ,因此相当于 {foo: foo, baz: baz}

Stack Overflow用户
修改于2020-09-29
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2020-09-29 05:48
得票数 14

从对象数组中收集不同字段的示例

let inputArray = [
  { id: 1, name: "name1", value: "value1" },
  { id: 2, name: "name2", value: "value2" },
let ids = inputArray.map( (item) => item.id);
let names = inputArray.map((item) => item.name);
let values = inputArray.map((item) => item.value);
console.log(ids);
console.log(names);
console.log(values);

结果:

[ 1, 2 ]
[ 'name1', 'name2' ]
[ 'value1', 'value2' ]
操作
回答于2020-12-26
得票数 3

在ES6中,如果您希望将字段作为字符串动态传递:

function getFields(array, field) {
    return array.map(a => a[field]);
let result = getFields(array, 'foo');
回答于2021-03-27
得票数 5

上述答案适用于单个属性,但当从数组中选择多个属性时,请使用以下内容

var arrayObj=[{Name,'A',Age:20,Email:'a.gmail.com'},{Name,'B',Age:30,Email:'b.gmail.com'},{Name,'C',Age:40,Email:'c.gmail.com'}]

现在我只选择两个字段

 var outPutArray=arrayObj.map(( {Name,Email} ) =>  ({Name,Email}) )
 console.log(outPutArray)
修改于2021-05-19
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2021-05-18 23:12
得票数 3

创建一个空数组,然后从列表中创建forEach元素,将该对象中需要的内容推送到空数组中。

 let objArray2 = [];
 objArray.forEach(arr => objArray2.push(arr.foo));
0
修改于2021-09-27
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2021-08-04 18:41
得票数 17

map() 方法创建一个新数组,其中填充了对调用数组中的每个元素调用所提供函数的结果。

let kvArray = [{key: 1, value: 10},
               {key: 2, value: 20},
               {key: 3, value: 30}]
let reformattedArray = kvArray.map(obj => {
   return obj.value
})

const kvArray = [['key1', 'value1'], ['key2', 'value2']]
// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray)
myMap.get('key1') // returns "value1"
// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)) // Will show you exactly the same Array as kvArray
// A succinct way to do the same, using the spread syntax
console.log([...myMap])
// Or use the keys() or values() iterators, and convert them to an array