[英]using .reduce() on an a list of objects
I have this sample data set: 我有这个样本数据集:
let list = [
{'first': 'morgan', 'id': 1},
{'first': 'eric', 'id': 1},
{'first': 'brian', 'id': 2 },
{'first': 'derek', 'id' : 2},
{'first': 'courtney', 'id': 3},
{'first': 'eric', 'id': 4},
{'first': 'jon', 'id':4},
]
I am trying to end up with this: 我想结束这个:
[[1, [morgan, eric]], [2, [brian, derek]], [3, [courtney]], [4, [eric, jon]]
I am using the .reduce()
function to map over the list. 我使用.reduce()
函数映射列表。 However, I'm somewhat stuck. 但是,我有点卡住了。
I got this working: 我有这个工作:
let b = list.reduce((final_list, new_item) => {
x = final_list.concat([[new_item.id, [new_item.first]]])
return x
}, [])
However, that flattens out the list into a list of lists of lists, but doesn't combine names that share a similar id. 但是,这会将列表展平为列表列表,但不会合并共享相似ID的名称。
I tried using .map()
the code below does not work 我尝试使用.map()
,下面的代码不起作用
I tried to map over the final_list (which is a list of [id, [names]] looking to see if the id of the new_item
exists in the smaller_list
and then add new_item.first
to the smaller_list[1]
(which should be the list of names). 我试图映射在final_list(这是[ID,[名]看看是否在的ID列表new_item
中存在smaller_list
,然后添加new_item.first
到smaller_list[1]
这应该是名单)。
Is this the right approach? 这是正确的方法吗?
let b = list.reduce((final_list, new_item) => {
final_list.map((smaller_list) => {
if (smaller_list.indexOf((new_item.id)) >=0) {
smaller_list[1].concat(new_item.first)
// not sure what to do here...
} else {
// not sure what to do here either...
}
})
x = final_list.concat([[item.id, [item.first]]])
return x
}, [])
In my approach, i'm using reduce to create a sparse array with the index as the list id. 在我的方法中,我使用reduce来创建一个以索引作为列表id的稀疏数组。 I then use Object.values
to squash it down. 然后我使用Object.values
来Object.values
它。
let list = [ {'first': 'morgan', 'id': 1}, {'first': 'eric', 'id': 1}, {'first': 'brian', 'id': 2 }, {'first': 'derek', 'id' : 2}, {'first': 'courtney', 'id': 3}, {'first': 'eric', 'id': 4}, {'first': 'jon', 'id':4} ]; let result = list.reduce( (acc, item, index) => { if(acc[item.id]){ acc[item.id][1].push(item.first); } else { acc[item.id] = [item.id, [item.first]]; } return acc; }, []); console.log(Object.values(result));
My solution was to first map over your list and combine the ones with similar ID and then loop over that result in order to change the format to the one requested. 我的解决方案是首先映射您的列表并组合具有相似ID的那些,然后循环该结果,以便将格式更改为所请求的格式。
let list = [ {'first': 'morgan', 'id': 1}, {'first': 'eric', 'id': 1}, {'first': 'brian', 'id': 2 }, {'first': 'derek', 'id' : 2}, {'first': 'courtney', 'id': 3}, {'first': 'eric', 'id': 4}, {'first': 'jon', 'id':4}, ] let temp = [], result = []; list.map(entry => { if(!temp[entry.id]) temp[entry.id] = [entry.first] else temp[entry.id].push(entry.first) }) temp.forEach((names, id) => { result.push([id, names]) }) console.log(JSON.stringify(result))
EDIT: I used an array as temp
because the ID is an integer and for the convenience of being able to use a forEach
loop. 编辑:我使用数组作为temp
因为ID是一个整数 ,为了方便使用forEach
循环。 If the key was something else then you would use a Hash table. 如果密钥是其他东西,那么你将使用哈希表。
Try first creating a map of IDs to names, then map that into your final array, eg 首先尝试为名称创建ID映射,然后将其映射到最终数组中,例如
let list = [ {'first': 'morgan', 'id': 1}, {'first': 'eric', 'id': 1}, {'first': 'brian', 'id': 2 }, {'first': 'derek', 'id' : 2}, {'first': 'courtney', 'id': 3}, {'first': 'eric', 'id': 4}, {'first': 'jon', 'id':4}, ] const idMap = list.reduce((map, item) => { if (Array.isArray(map[item.id])) { map[item.id].push(item.first) } else { map[item.id] = [item.first] } return map }, {}) const b = Object.keys(idMap).map(id => [parseInt(id), idMap[id]]) console.info(JSON.stringify(b))
you want to do it with reduce, and doing it with a single reduce would be nice. 你想用reduce做到这一点,用一个reduce做它会很好。 here are 3 ways 这里有3种方式
verbose, more loops 详细,更多循环
const tuples1 = list.reduce( (tuples, obj) => {
if( tuples.some( ( [id, _] ) => id === obj.id ) ){
tuples.find( ( [id, _] ) => id === obj.id )[1].push(obj.first)
}else{
tuples.push([obj.id, [obj.first]])
}
return tuples
}, [])
same as tuples1, terse 和tuples1一样,简洁
const tuples2 = list.reduce( (tuples, obj) =>
( tuples.some( ( [id, _] ) => id === obj.id ) ) ?
( tuples.find( ( [id, _] ) => id === obj.id )[1].push(obj.first), tuples ) :
( tuples.push([obj.id, [obj.first]]), tuples ), [])
more verbose, less loops 更冗长,更少的循环
const tuples3 = list.reduce( (tuples, obj) => {
const existingId = tuples.find( ( [id, _] ) => id === obj.id )
if( existingId ){
existingId[1].push(obj.first)
}else{
tuples.push([obj.id, [obj.first]])
}
return tuples
}, [])
each produce the same result 每个产生相同的结果
[ [ 1, [ 'morgan', 'eric' ] ],
[ 2, [ 'brian', 'derek' ] ],
[ 3, [ 'courtney' ] ],
[ 4, [ 'eric', 'jon' ] ] ]
Just in case you're also looking for a non reduce
solution. 以防你也在寻找非reduce
解决方案。
Here is one. 这是一个。 It is a bit long winded but that is because I'm trying to decompose the problem into a few parts. 这有点长,但这是因为我试图将问题分解为几个部分。
I first go through the list
and sort the elements into their respective Id
. 我首先浏览list
并将元素分类到各自的Id
。
Then For each id
in the sorted object. 然后为排序对象中的每个id
。 I loop through it again by first instantiating an outer element first. 我首先通过首先实例化外部元素来再次遍历它。
id
key into the element first. 首先将id
键推入元素中。 first
property and add it into the nested element. 遍历所有关联元素并提取其first
属性并将其添加到嵌套元素中。 result
array. 我只是将它们合并到父元素中并将其附加到result
数组中。 Hopfully it is not too complicated for you but I suspect it will be easier to see the code in action through an IDE. 对你而言,它并不是太复杂,但我怀疑通过IDE看到代码的运行会更容易。
var list = [ {'first': 'morgan', 'id': 1}, {'first': 'eric', 'id': 1}, {'first': 'brian', 'id': 2 }, {'first': 'derek', 'id' : 2}, {'first': 'courtney', 'id': 3}, {'first': 'eric', 'id': 4}, {'first': 'jon', 'id':4}, ] var result = []; var keyById = {}; // Sort the list of items to be keyed by: Id => [ item, item ] list.forEach(function(item) { if (!keyById.hasOwnProperty(item.id)) { keyById[item.id] = []; } keyById[item.id].push(item); }); // Build the data structure for (var id in keyById) { var item = []; // The outer element var nestedItem = []; // The nested element belonging to the outer item.push(id); keyById[id].forEach(function(element) { nestedItem.push(element.first); }); item.push(nestedItem); result.push(item); } console.log(JSON.stringify(result, '', 2));
list
and build an object using the id
s as key
s with value
s of array
s of the first
names. 遍历list
和建立使用的对象id
S作为key
s的value
第array
的第first
名称。 list
(if you plan to overwrite it). 空list
(如果您打算覆盖它)。 array
s for each id
with its next sibling element being an array
of the names from the value
associated with that id
, and push
them into list
(or a fresh array
if maintaining the original list
). 遍历生成的对象,为每个id
生成array
,其下一个兄弟元素是与该id
相关联的value
的名称array
, push
它们push
入list
(如果保留原始list
则将其push
送到新array
)。 var list = [ {'first': 'morgan', 'id': 1}, {'first': 'eric', 'id': 1}, {'first': 'brian', 'id': 2 }, {'first': 'derek', 'id' : 2}, {'first': 'courtney', 'id': 3}, {'first': 'eric', 'id': 4}, {'first': 'jon', 'id':4}, ], o = {}, p; list.forEach( ( v ) => { if ( !o[ v.id ] ) { o[ v.id ] = []; } o[ v.id ].push( v.first ); } ); list = []; // if overwriting for ( p in o ) { if ( o.hasOwnProperty( p ) ) { list.push( [ parseInt( p ), o[ p ] ] ); } } console.log( JSON.stringify( list ).replace( /,/g, ", " ) );
Edited to add parseInt()
(noticed in another answer) since the question's example expected output does indeed show numerals as integers, not strings. 编辑添加parseInt()
(在另一个答案中注意到),因为问题的示例预期输出确实将数字显示为整数,而不是字符串。
And changed the demo output to stringify
ed JSON
(also noticed (easier to read) in other answers). 并将演示输出更改为stringify
ed JSON
(在其他答案中也注意到(更容易阅读))。
It's probably easiest to write a plain loop for this: 为此编写一个简单的循环可能是最简单的:
let final_list = []
for (k = 0; k < list.length; k += 2) {
let item1 = list[k]
let item2 = list[k + 1]
final_list.push([item1.id, [item1.first, item2.first]])
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.