在对象列表上使用.reduce()

时间:2017-07-07 00:45:57

标签: javascript

我有这个样本数据集:

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},
]

我想结束这个:

[[1, [morgan, eric]], [2, [brian, derek]], [3, [courtney]], [4, [eric, jon]]

我使用.reduce()函数映射列表。但是,我有点卡住了。

我有这个工作:

let b = list.reduce((final_list, new_item) => {
  x = final_list.concat([[new_item.id, [new_item.first]]])
  return x
}, [])

但是,这会将列表展平为列表列表,但不会合并共享相似ID的名称。

我尝试使用.map() 以下代码无效

我尝试映射final_list(这是[id,[names]]的列表,以查看new_item中是否存在smaller_list的ID,然后添加{{1到new_item.first(应该是名字列表)。

这是正确的做法吗?

smaller_list[1]

7 个答案:

答案 0 :(得分:5)

在我的方法中,我使用reduce创建一个稀疏数组,索引作为列表id。然后我使用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));

答案 1 :(得分:3)

我的解决方案是先对您的列表进行映射,然后将具有相似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))

编辑:我使用数组作为temp,因为ID是整数并且为了方便使用forEach环。如果密钥是其他东西,那么你将使用哈希表。

答案 2 :(得分:3)

首先尝试为名称创建ID地图,然后将其映射到最终数组,例如



Split: lista

li := Array new: 30.
aux := Array new: 30.
j := 0.
1 to: (lista size / 30) ceiling do: [ :i | 
    1 to: 30 do: [ :k | aux at: k put: (lista at: k + j) ].
    j := j + 30.
    li at: i put: aux ].
^ li




答案 3 :(得分:1)

你想用reduce来做,并且用一个reduce来做它会很好。这里有3种方式

详细,更多循环

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
}, [])

与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 ), [])

更详细,更少循环

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
}, [])

每个产生相同的结果

[ [ 1, [ 'morgan', 'eric' ] ],
  [ 2, [ 'brian', 'derek' ] ],
  [ 3, [ 'courtney' ] ],
  [ 4, [ 'eric', 'jon' ] ] ]

答案 4 :(得分:0)

万一您也在寻找非reduce解决方案。

这是一个。这有点长,但这是因为我试图将问题分解成几个部分。

  1. 我首先浏览list并将元素分类到各自的Id

  2. 然后对于已排序对象中的每个id。我首先通过首先实例化外部元素来再次遍历它。

  3. 首先将id键推入元素。
  4. 遍历所有关联元素并提取其first属性并将其添加到嵌套元素中。
  5. 构建嵌套元素后。我只是将它们合并到父元素中并将其附加到result数组中。
  6. 对你而言,这并不是太复杂,但我怀疑通过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));
    
    
    

答案 5 :(得分:0)

不是很性感,但它有效

  • list进行迭代,并使用id作为key来构建一个对象value的{​​{1}}个array s first名。
  • 清空list(如果您打算覆盖它)。
  • 浏览结果对象,为array生成id个,其下一个同级元素是与array相关联的value的{​​{1}}个id如果维护原始push,则将list转换为array(或新list

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, ", " ) );

已编辑以添加parseInt()(在另一个答案中注意到),因为问题的示例预期输出确实将数字显示为整数,而不是字符串。
并将演示输出更改为stringify ed JSON(在其他答案中也注意到(更易于阅读))。

答案 6 :(得分:-2)

为此编写一个简单的循环可能最容易:

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]])
}