reduce按条件分组输出错误,为什么?

要求:

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];
// Output: {
//   25: [{ name: 'Alice', age: 25 }, { name: 'David', age: 25 }],
//   30: [{ name: 'Bob', age: 30 }, { name: 'Emily', age: 30 }],
//   35: [{ name: 'Charlie', age: 35 }]
// }

代码:

let fn = (arr = []) => {
  return arr.reduce((accumulator, currentValue) => {
    return accumulator[currentValue.age]
      ? (accumulator[currentValue.age] = accumulator[currentValue.age].concat(currentValue))
      : ((accumulator[currentValue.age] = [currentValue]));
  }, {});
};

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];

console.log(fn(people));

输出:
[ { name: 'Emily', age: 30 } ]

阅读 3.3k
7 个回答
accumulator
上一次调用 callbackFn 的结果。在第一次调用时,如果指定了 initialValue 则为指定的值,否则为 array[0] 的值。—— MDN

所谓上一次调用结果即你每一次return的值会交给下一次迭代,而在你的代码中第一次accumulator是初始值{},而在你的return语句是三元表达式,而表达式是赋值语句,赋值语句的结果是等号右侧的结果,一个是concat,一个是[currentValue],这两个都是数组,它们作为下一次的accumulator,所以你下一次迭代就不再是对象了。所以你需要把每次迭代的对象return回去:

let fn = (arr = []) => {
  return arr.reduce((accumulator, currentValue) => {
    return (accumulator[currentValue.age]
      ? (accumulator[currentValue.age] = accumulator[currentValue.age].concat(currentValue))
      : ((accumulator[currentValue.age] = [currentValue])),
    accumulator);
  }, {});
};

你的错误在于三元表达式返回的值是数组,而你把这个数组再返回了,导致下一次接受的 accumulator 是数组而不是对象,原对象的信息实际上已经丢失。

function reduceByAge(list = []){
  return list.reduce(( reduced, present) => {
    const {
      [present.age]: subList = []
    } = reduced;
    subList.push(present);
    reduced[present.age] = subList;
    return reduced;
  }, {});
}
const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];

let fn = (arr = []) => {
  return arr.reduce((accumulator, currentValue) => {
    let { age } = currentValue;
    accumulator[age] ? accumulator[age].push(currentValue): accumulator[age] = [currentValue]
    return accumulator;
  }, {});
};

console.log(fn(people))
const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];

let arr = people.reduce((prev,curr) => {
  let key = curr["age"];
  if (!prev[key]) {
    prev[key] = []
  }
  prev[key].push(curr);
  return prev
},{})

你的这一行代码不是表达式(expression),而是语句(statement)

所以要改写为 return accumulator

let fn = (arr = []) => {
  return arr.reduce((accumulator, currentValue) => {
    accumulator[currentValue.age]
      ? (accumulator[currentValue.age] = accumulator[currentValue.age].concat(currentValue))
      : ((accumulator[currentValue.age] = [currentValue]));
    return accumulator
  }, {});
};

因为数组reduce方法要求传入的reducer函数必须返回计算结果,作为下一次调用该函数时的第一个参数。这里简单模拟下reduce方法的实现,你看下就知道为什么要这么写了:

function reduce(arr, cb, init) {
    for (var i = 0; i < arr.length; ++i) {
        init = cb(init, arr[i], i, arr);
    }
    return init;
}

let fn = (arr = []) => {
    return reduce(arr, (accumulator, currentValue) => {
        accumulator[currentValue.age] ?
            (accumulator[currentValue.age] = accumulator[currentValue.age].concat(currentValue)) :
            ((accumulator[currentValue.age] = [currentValue]));
        return accumulator;
    }, {});
};

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];

console.log(fn(people));
const fn = (arr = []) => {
  return arr.reduce((acc, item) => {
    const { age } = item;
    if (!acc[age]) {
      acc[age] = [];
    }
    acc[age].push(item);
    return acc;
  }, {});
}

const people = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 },
  { name: 'David', age: 25 },
  { name: 'Emily', age: 30 }
];
fn(people);
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏