1924

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

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

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

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

函数getFields(输入,字段){var输出=[];对于(var i=0;i<输入长度;++i)output.push(输入[i][字段]);返回输出;}var result=getFields(objArray,“foo”);//返回[1,3,5]

是否有一种更优雅或惯用的方法来实现这一点,从而不需要自定义实用程序函数?


关于的注释建议的副本,它涵盖了如何转换单个对象到数组。

9
  • 4
    Prototype库向Array原型添加了一个“pull”函数(我认为),因此您可以编写var foos=objArray.pulch(“foo”);.
    – 波蒂
    评论 2013年10月25日13:16
  • @海德-jsperf.com/map-vs-native-for-loop-请看一下这个,希望普通循环本身是一个好的解决方案 评论 2013年10月25日13:21
  • 1
    @N20084753对于一个公平的测试,您还应该比较本地阵列原型.map存在的功能
    – 参宿一
    评论 2013年10月25日13:22
  • 4
    OP,我更喜欢你的方法,而不是其他建议的方法。没有什么问题。
    – 用户1017882
    评论 2016年12月12日14:37
  • 1
    @我想你说的是函数_.pulch(objArray,“foo”),但这是Underscore库的一部分。最好的方法是使用.map(地图)在ES6中可用
    – X射线
    评论 2022年12月7日12:45

26个答案26

重置为默认值
2611

以下是实现这一目标的较短方法:

让结果=objArray.map(a=>a.foo);

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

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

11
  • 4
    好吧,这和托蒂梅德利的另一个答案是一样的,但不是这样,(在我看来)这实际上比其他答案好答案,所以……将其更改为接受的答案。
    – 海德
    评论 2017年10月11日17:52
  • 2
    顺便说一句,我真的很喜欢那个=>符号对我来说是一件新鲜事,所以我认为如果该解决方案确实可行,那么需要对其兼容性进行审查。 评论 2017年10月13日11:49
  • 7
    @PauloRoberto Arrow函数包括除IE外,其他地方基本上都支持。 评论 2017年10月27日6:48
  • 5
    当然,这是允许的,但IMHO没有什么能使这个答案客观上更好,除了它使用的语法不可用当时你问了这个问题,有些浏览器甚至不支持。我还要注意到,这个答案是在这个答案发布前近一年对最初接受的答案所做评论的直接副本。
    – 参宿一
    评论 2018年2月10日19:55
  • 56
    @Alnitak在我看来,使用更新的功能,客观上更好。这个片段非常常见,所以我不认为这是剽窃。把过时的答案钉在最上面真的没有任何价值。
    – 罗布
    评论 2018年3月2日5:59
742

是的,但它依赖于JavaScript的ES5功能。这意味着它在IE8或更旧版本中不起作用。

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

在与ES6兼容的JS解释器上,您可以使用箭头函数为简洁起见:

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

Array.prototype.map文档

0
77

谈到只支持JS的解决方案,我发现一个简单的索引可能并不优雅对于循环比其替代方案更具性能。

从100000元素数组中提取单个属性(通过jsPerf)

传统for循环368操作/秒

变量值=[];for(var i=0;i<testArray.length;i++){vals.push(testArray[i].val);}

ES6用于。。循环的303操作/秒

变量值=[];for(testArray的var项){vals.push(item.val);}

数组原型.map19操作/秒

var vals=testArray.map(函数(a){return a.val;});

TL;DR-.map()速度较慢,但如果您觉得可读性比性能更重要,可以随意使用它。

编辑#2:2019年6月-jsPerf链接已断开,已删除。

  • 4
    我只是重新测试了一下jsBench公司(多亏了米尔科·武库什奇创建jsPerf的替代品),结果仍然相同的-对于是最快的,用于。。属于速度稍慢,地图大约慢了一半。 评论 2021年10月19日11:25
  • 它们与原始答案中的不一样,至少对我来说是这样的。在原始答案中用于。。属于速度约为16倍地图。今天运行基准测试,对于。。属于速度是…的2倍地图. 评论 2022年9月30日18:04
  • 1
    关于性能考虑与代码可读性的一个非常有趣的观点,让我阅读了这篇文章,这篇文章进一步阐明了这个主题。leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of 评论 2023年7月25日6:39
58

结账洛达什的_.拔出()功能或下划线_.pull()功能。两者都可以在单个函数调用中实现您想要的功能!

var result=_.pulch(objArray,'foo');

更新: _.拔出()自Lodash v4.0.0起已删除,赞成_.map()与类似的东西结合在一起尼特的回答._.拔出()仍在Undercore中提供.

更新2:正如马克指出的那样在评论中在Lodash v4和4.3之间添加了一个新功能,再次提供此功能。_.property()是一个速记函数,返回用于获取对象中属性值的函数。

此外,_.map()(地图)现在允许将字符串作为第二个参数传入,该参数被传入_.property()因此,以下两行与Lodash 4之前的代码示例等效。

var result=_.map(objArray,'foo');var结果=_.map(objArray,_.properties('fo'));

_.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']));

两者_.map()上述示例中的调用将返回[5, 2, 9].

如果您对函数式编程有点了解,请看兰达的 R.拨动()函数,看起来像这样:

var result=R.pull('fo')(objArray);//或者只是R.pull('foo',objArray)
0
48

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

let inputArray=[{id:1,名称:“name1”,值:“value1”},{id:2,名称:“name2”,值:“value2”},];让ids=inputArray.map((item)=>item.id);let names=inputArray.map((item)=>item.name);let values=inputArray.map((item)=>item.value);console.log(id);console.log(名称);console.log(值);

结果:

[ 1, 2 ][“名称1”,“名称2”][“value1”,“value2”]
24

最好使用一些库,如lodash或下划线,以确保跨浏览器。

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

_.map(objArray,“foo”)

和底芯

_.pulch(objArray,“foo”)

两者都会返回

[1, 2, 3]
19

使用数组原型.map:

函数getFields(输入,字段){返回input.map(函数(o){返回o[字段];});}

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

17

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

const objArray=[{foo:1,bar:2},{foo:3,bar:4},}foo:5,bar:6}]objArray.map(({foo})=>foo)
0
15

我知道已经提供了很多答案,涵盖了大量解决方案。

但我想补充一些我在以上所有答案中都没有找到的东西。

例如,我将使用以下类型的数据

常量数组=[{name:“foo”,年龄:23,技能:[“reactjs”,“nodejs”和“nextjs”]},{name:“bar”,年龄:25岁,技能:[“angular”,“java”]}]

如果要从Object数组的所有索引中提取单个属性,那么可以只使用map函数,因为许多社区成员已经回答了这个问题,为了便于参考,我将在此处编写代码:

array.map(a=>a.skills);

上述代码片段将生成长度为2的数组,这意味着它将返回两个索引的技能字段,


因此,如果您想从数组对象中获取单个字段特定的字段,例如只使用条的技能,下面是通过组合过滤器和映射函数实现的示例代码

常量数组=[{姓名:“foo”,年龄:23岁,技能:[“reactjs”,“nodejs”,“nextjs”]},{name:“bar”,年龄:25岁,技能:[“angular”,“java”]}]函数getField(数组,字段){return array.filter(a=>a.name===字段).map(a=>a.skills);}console.log(getField(数组,“bar”))


最后,如果你想在这里生成一个完全动态/通用的代码,那就是

常量数组=[{name:“foo”,年龄:23,技能:[“reactjs”,“nodejs”和“nextjs”]},{name:“bar”,年龄:25岁,技能:[“angular”,“java”]}]函数getFiled(array,fieldOf,fieldName){return array.filter(a=>a.name===fieldOf).map(a=>a[fieldName]);}console.log(getFiled(数组,“bar”,“skills”))

12

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

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

这是作为{foo,baz}左边是使用对象析构函数箭头右侧相当于{foo:foo,baz:baz}由于ES6增强的对象文字.

0
10

同时地图从对象列表中选择“列”是一个合适的解决方案,但它有缺点。如果不显式检查列是否存在,它将抛出一个错误并(最多)为您提供未定义. 我会选择减少解决方案,它可以简单地忽略该属性,甚至为您设置默认值。

函数getFields(列表,字段){//将提供的列表缩减为只包含请求字段的数组return-list.reduce(函数(进位,项){//检查项是否实际上是一个对象并且包含字段if(项的类型===“对象”&项中的字段){推进(项目[字段]);}//返回“carry”(匹配字段值的列表)返回携带;}, []);}

jsbin示例

即使所提供列表中的一个项不是对象或不包含字段,也可以使用此方法。

如果项不是对象或不包含字段,甚至可以通过协商默认值使其更加灵活。

函数getFields(列表、字段或其他){//将提供的列表缩减为包含请求字段或可选值的数组return-list.reduce(函数(进位,项){//如果项是对象并包含字段,则添加其值,否则添加的值carry.push(项目类型===“对象”&项目中的字段?项目[字段]:否则);//返回“进位”(匹配字段值的列表)返回携带;}, []);}

jsbin示例

这与map相同,因为返回数组的长度与提供的数组的长度相同。(在这种情况下地图比a稍微便宜减少):

函数getFields(列表、字段或其他){//将提供的列表映射到包含请求字段或可选值的数组return-list.map(函数(项){//如果项是对象并包含字段,则添加其值,否则添加的值返回项的类型===“对象”&项中的字段?项目[字段]:否则;}, []);}

jsbin示例

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

函数getFields(列表、字段或其他){//确定是否使用“否则”var alt=其他类型!==='未定义';//将提供的列表缩减为只包含请求字段的数组return-list.reduce(函数(进位,项){//如果项是一个对象并包含字段,则添加其值和“否则”值(如果已提供)if(项的类型===“对象”&项中的字段){推进(项目[字段]);}else if(alt){推进(否则);}//返回“carry”(匹配字段值的列表)返回携带;}, []);}

jsbin示例

正如上面的示例(希望如此)阐明了它的工作方式,让我们通过使用数组.concat功能。

函数getFields(列表、字段或其他){var alt=其他类型!=='未定义';return-list.reduce(函数(进位,项){return carry.concat(项类型===“对象”&项中的字段?项[字段]:(alt?否则:[]));}, []);}

jsbin示例

10

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

var arrayObj=[{姓名,'A',年龄:20,电子邮件:'A.gmail.com'},{姓名;'B',年龄;30,电子邮件:‘B.gmail.com'{姓名、'C',年龄∶40,电子邮件:’C.gmail.com’}]

现在我只选择了两个字段

var outPutArray=arrayObj.map(({Name,Email})=>console.log(outPutArray)
0
9

如果还想支持类似阵列的对象,请使用阵列起始位置(ES2015):

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

它的优势超过了Array.prototype.map()方法是输入也可以是设置:

let arrayLike=新集合([{foo:1},{foo:2},});
9

如果您有嵌套数组,可以这样工作:

常量objArray=[{id:1,项目:{foo:4,栏:2}},{id:2,项目:{foo:3,栏:2}},{id:3,项目:{foo:1,栏:2}}];let结果=objArray.map(({id,items:{foo}})=>({id、foo})console.log(结果)

8

一般来说,如果你想外推数组内的对象值(如问题中所述),那么你可以使用reduce、map和数组析构化。

欧洲标准6

设a=[{z:‘单词’,c:‘再次’,d:‘一些’},{u:‘1’,r:‘2’,i:‘3’}];设b=a.reduce((acc,obj)=>[…acc,Object.values(obj).map(y=>y)],[]);控制台.log(b)

等效使用中的的循环将是:

for(让我在a中){设温度=[];for(在a[i]中设j){推压温度(a[i][j]);}array.prush(临时);}

生产产量:[“单词”、“再次”、“一些”、“1”、“2”、“3”]

6

易于提取倍数对象数组的属性:

让arrayOfObjects=[{id:1,name:'one',desc:'something'},{id:2,名称:'two',描述:'something else'}];//下面将只提取id和名称让结果=arrayOfObjects.map(({id,name})=>;

结果[{id:1,name:'one'},{id:2,name:'two'}]

根据需要在map函数中添加或删除属性

6

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

函数getFields(数组,字段){return array.map(a=>a[field]);}let result=getFields(数组,'foo');
6

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

其他答案指出了地图的使用,它是自然的(尤其是对于习惯于功能风格的人来说)和简洁的。我强烈建议您使用它(如果您不介意使用少数IE8-it人员)。所以,如果“更好”意味着“更简洁”、“可维护”、“易于理解”,那么是的,它就更好了。

另一方面,这种美丽并非没有额外的成本。我不太喜欢微型长椅,但我已经做了一个小的在此处测试结果是可以预测的,旧的丑陋方法似乎比map函数更快。所以,如果“更好”意味着“更快”,那么就不要,继续沿用老派的时尚。

再一次,这只是一个小把戏,决不主张反对使用地图,这只是我的两分钱:)。

0
5

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

设objArray2=[];objArray.forEach(arr=>objArray 2.push(arr.foo));
1
  • 1
    评论被编辑了,谢谢你的解释。
    – 奇米亚
    评论 2021年5月19日6:57
4

从对象数组中,使用for循环将属性的值提取为数组。

//输入objArray=[{foo:1,bar:2},{foo:3,bar:4],{foo:5,bar:6}];//代码设输出=[];for(objArray的let项){output.push(item.foo);}//输出[ 1, 3, 5 ]

上述答案有助于提取单个属性,如果您想从对象数组中提取多个属性,该怎么办。这是解决方案!!在这种情况下,我们可以简单地使用_.pick(object,[paths])

_.pick(对象,[路径])

假设objArray具有如下三个属性的对象

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

现在,我们想从每个对象中提取foo和bar属性,并将它们存储在单独的数组中。首先,我们将使用map迭代数组元素,然后对其应用Lodash Library Standard_.pick()方法。

现在我们可以提取“foo”和“bar”属性。

var newArray=objArray.map((element)=>{return_.pick(element,['foo','bar'])})console.log(newArray);

结果是[{foo:1,bar:2},{foo:3,bar:4},}foo:5,bar:6}]

享受!!!

2
  • 1
    在哪里_.选择来自哪里?这不是一个标准功能。
    – 奈维斯
    评论 2019年2月6日21:05
  • 我刚刚更新了答案,_.pick()是Lodash库的标准方法。 评论 2019年2月7日14:42

下面是使用的另一个形状地图方法返回特定属性:

const objArray=[{foo:1,bar:2},{foo:3,bar:4},{foo:5,bar:6}];const getProp=prop=>obj=>obj[prop];const getFoo=getProp('foo');const-fooes=objArray.map(getFoo);console.log(fooes);

如果您甚至不知道您正在使用的对象的确切属性,我只会改进其中一个答案:

let result=objArray.map(a=>a[Object.getOwnPropertyNames(a)]);
2

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

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

var obj={value1:“val1”,value2:“val2”,Ndb_No:“testing”,myVal:未定义};var keysFiltered=对象.keys(obj).filter(函数(项){return!(项==“Ndb_No”||obj[item]==未定义)});var valuesFiltered=keysFiltered.map(函数(项){return obj[item]});

https://jsfiddle.net/ohea7mgk/

1

如果从对象数组中提取多个键,那么以下解决方案更具动态性。

let newArray:any=[]objArray.forEach(函数(项:任意){newArray.push(item.keyName,item?.keyName)})
0

解构并从对象数组中获取特定属性:

const customerList=经销商用户数据?。聚会详情.map(({partyId,custAccountId})=>({聚会ID,custAccountId,customerId:dealerUserData_身份证件,userId:dealerUserData?。授权用户ID,}),);

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.