hyd*_*yde 851 javascript javascript-objects
我有JavaScript对象数组,具有以下结构:
objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];
Run Code Online (Sandbox Code Playgroud)
我想提取一个包含key值的数组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 ]
Run Code Online (Sandbox Code Playgroud)
有没有更优雅和高效的方法来实现?
关于建议重复的注意事项,该问题询问如何将对象转换为数组,这个问题询问如何从对象数组中提取单个属性.
Jal*_*sem 1011
这是实现它的一种较短的方法:
Array.prototype.map()
要么
Array.prototype.map()
您还可以在MDN上检查Array.prototype.map()文档
Nie*_*sol 598
是的,但它依赖于JavaScript的ES5功能.这意味着它无法在IE8或更早版本中运行.
var result = objArray.map(function(a) {return a.foo;});
Run Code Online (Sandbox Code Playgroud)
在ES6兼容的JS解释器上,您可以使用箭头功能以简化:
var result = objArray.map(a => a.foo);
Run Code Online (Sandbox Code Playgroud)
cpd*_*pdt 50
查看Lodash的_.pluck()
功能或Underscore 的_.pluck()
功能.两者都可以在单个函数调用中完成您想要的操作!
var result = _.pluck(objArray, 'foo');
Run Code Online (Sandbox Code Playgroud)
更新: _.pluck()
已从Lodash v4.0.0中删除,有利于_.map()
与Niet的答案类似的组合._.pluck()
仍然可以在Underscore中使用.
更新2:正如Mark 在评论中指出的那样,在Lodash v4和4.3之间,添加了一个新功能,再次提供此功能._.property()
是一个简写函数,它返回一个函数,用于获取对象中属性的值.
此外,_.map()
现在允许将字符串作为第二个参数传入,并将其传入_.property()
.因此,以下两行等同于上述Lodash 4中的代码示例.
var result = _.map(objArray, 'foo');
var result = _.map(objArray, _.property('foo'));
Run Code Online (Sandbox Code Playgroud)
_.property()
,因此_.map()
,还允许您提供以点分隔的字符串或数组,以访问子属性:
var objArray = [
{
someProperty: { aNumber: 5 }
},
{
someProperty: { aNumber: 2 }
},
{
someProperty: { aNumber: 9 }
}
];
var result = _.map(objArray, _.property('someProperty.aNumber'));
var result = _.map(objArray, _.property(['someProperty', 'aNumber']));
Run Code Online (Sandbox Code Playgroud)
_.map()
以上示例中的两个调用都将返回[5, 2, 9]
.
如果您对函数式编程有更多了解,请查看Ramda的 R.pluck()
函数,它看起来像这样:
var result = R.pluck('foo')(objArray); // or just R.pluck('foo', objArray)
Run Code Online (Sandbox Code Playgroud)
psc*_*scl 37
对于仅有JS的解决方案,我发现,尽管它可能不优雅,但简单的索引for
循环比其替代方案更具性能.
https://jsperf.com/extract-prop-from-object-array/
从100000元素数组中提取单个属性
传统的for循环 368 Ops/sec
var vals=[];
for(var i=0;i<testArray.length;i++){
vals.push(testArray[i].val);
}
Run Code Online (Sandbox Code Playgroud)
ES6 for..of循环 303 Ops/sec
var vals=[];
for(var item of testArray){
vals.push(item.val);
}
Run Code Online (Sandbox Code Playgroud)
Array.prototype.map 19 Ops/sec
var vals = testArray.map(function(a) {return a.val;});
Run Code Online (Sandbox Code Playgroud)
编辑:Ops/s更新时间:10/2017.TL; DR - .map()很慢.但有时可读性比性能更有价值.
Aln*_*tak 15
function getFields(input, field) {
return input.map(function(o) {
return o[field];
});
}
Run Code Online (Sandbox Code Playgroud)
有关预先ES5浏览器的垫片,请参阅上面的链接.
Tej*_*tel 13
最好使用某种类型的库,如lodash或下划线来实现跨浏览器保证.
在lodash中,您可以通过以下方法获取数组中的属性值
_.map(objArray,"foo")
Run Code Online (Sandbox Code Playgroud)
并以下划线
_.pluck(objArray,"foo")
Run Code Online (Sandbox Code Playgroud)
两者都将返回[1,3,5]
Abi*_*lah 13
我知道已经提供了很多答案并且涵盖了广泛的解决方案。
但我想添加一些我在上述所有答案中都没有找到的内容。
例如我将使用以下类型的数据
const array = [
{name:"foo",age:23, skills:["reactjs","nodejs","nextjs"]},
{name:"bar",age:25, skills:["angular","java"]}
]
Run Code Online (Sandbox Code Playgroud)
如果您要从对象数组的所有索引中提取单个属性,那么只使用映射函数就可以了,正如许多社区成员已经回答的那样,作为参考,我将在此处编写代码:
array.map(a => a.skills);
Run Code Online (Sandbox Code Playgroud)
上面的代码片段将生成长度为 2 的数组,这意味着它将返回两个索引的技能字段,
因此,如果您想从数组对象中获取单个字段特定的字段,例如仅 bar 的技能,这里是通过组合过滤器和映射函数来实现的示例代码
const array = [
{name:"foo",age:23, skills:["reactjs","nodejs","nextjs"]},
{name:"bar",age:25, skills:["angular","java"]}
]
Run Code Online (Sandbox Code Playgroud)
最后,如果你想要一个完全动态/通用的代码,那就是
array.map(a => a.skills);
Run Code Online (Sandbox Code Playgroud)
jaf*_*mlp 10
从对象数组中收集不同字段的示例
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);
Run Code Online (Sandbox Code Playgroud)
结果 :
[ 1, 2 ]
[ 'name1', 'name2' ]
[ 'value1', 'value2' ]
Run Code Online (Sandbox Code Playgroud)
小智 10
上面的答案适用于单个属性,但是当从数组中选择多个属性时,请使用此答案
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'}]
Run Code Online (Sandbox Code Playgroud)
现在我只选择两个字段
var outPutArray=arrayObj.map(( {Name,Email} ) => ({Name,Email}) )
console.log(outPutArray)
Run Code Online (Sandbox Code Playgroud)
在ES6中,您可以执行以下操作:
const objArray = [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
objArray.map(({ foo }) => foo)
Run Code Online (Sandbox Code Playgroud)
通常,如果您想推断数组内的对象值(如问题中所述),那么您可以使用reduce、map 和数组解构。
ES6
let a = [{ z: 'word', c: 'again', d: 'some' }, { u: '1', r: '2', i: '3' }];
let b = a.reduce((acc, obj) => [...acc, Object.values(obj).map(y => y)], []);
console.log(b)
Run Code Online (Sandbox Code Playgroud)
使用for in循环的等效方法是:
for (let i in a) {
let temp = [];
for (let j in a[i]) {
temp.push(a[i][j]);
}
array.push(temp);
}
Run Code Online (Sandbox Code Playgroud)
产生的输出: ["word", "again", "some", "1", "2", "3"]
虽然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;
}, []);
}
Run Code Online (Sandbox Code Playgroud)
即使提供的列表中的某个项不是对象或不包含该字段,这也可以工作.
如果项目不是对象或不包含该字段,则通过协商默认值可以使其更加灵活.
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;
}, []);
}
Run Code Online (Sandbox Code Playgroud)
这与map相同,因为返回的数组的长度与提供的数组相同.(在这种情况下,a map
比a稍微便宜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;
}, []);
}
Run Code Online (Sandbox Code Playgroud)
然后是最灵活的解决方案,只需提供替代值即可在两种行为之间切换.
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;
}, []);
}
Run Code Online (Sandbox Code Playgroud)
正如上面的例子(希望)对它的工作方式有所了解,让我们通过利用这个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 : []));
}, []);
}
Run Code Online (Sandbox Code Playgroud)
如果您想在 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 }))
Run Code Online (Sandbox Code Playgroud)
这就像{foo, baz}
左侧使用对象析构一样工作,而箭头右侧的等效{foo: foo, baz: baz}
于ES6 的增强对象文字。
如果您还想支持类似数组的对象,请使用Array.from (ES2015):
Array.from(arrayLike, x => x.foo);
Run Code Online (Sandbox Code Playgroud)
The advantage it has over Array.prototype.map() method is the input can also be a Set:
let arrayLike = new Set([{foo: 1}, {foo: 2}, {foo: 3}]);
Run Code Online (Sandbox Code Playgroud)
如果你有嵌套数组,你可以让它像这样工作:
const objArray = [
{ id: 1, items: { foo:4, bar: 2}},
{ id: 2, items: { foo:3, bar: 2}},
{ id: 3, items: { foo:1, bar: 2}}
];
let result = objArray.map(({id, items: {foo}}) => ({id, foo}))
console.log(result)
Run Code Online (Sandbox Code Playgroud)
从对象数组中轻松提取多个属性:
let arrayOfObjects = [
{id:1, name:'one', desc:'something'},
{id:2, name:'two', desc:'something else'}
];
//below will extract just the id and name
let result = arrayOfObjects.map(({id, name}) => ({id, name}));
Run Code Online (Sandbox Code Playgroud)
result
将会 [{id:1, name:'one'},{id:2, name:'two'}]
根据需要在地图功能中添加或删除属性
在 ES6 中,如果您想动态地将字段作为字符串传递:
function getFields(array, field) {
return array.map(a => a[field]);
}
let result = getFields(array, 'foo');
Run Code Online (Sandbox Code Playgroud)
创建一个空数组,然后对于列表中的每个元素,将您想要的内容从该对象推送到空数组中。
let objArray2 = [];
objArray.forEach(arr => objArray2.push(arr.foo));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
604274 次 |
最近记录: |