如何在Javascript中查找对象数组中特定键的所有唯一值?

4

我有一个Javascript对象数组,我试图获取每个对象特定属性的所有唯一值的数组。我尝试使用reduce()实现这个目标,我的示例代码如下,但是它会出现错误:"Cannot read properties of undefined (reading 'includes')"即使我提供了一个空数组作为初始值。预期结果是一个包含

['New York', 'San Francisco', 'Chicago', 'Los Angeles']

最终目标是创建一张柱状图,X轴上为城市名称,Y轴上为每个城市的平均工资,因此我需要唯一的城市列表。有没有避免这种错误的方法,或者更好的方法来完成这个任务呢?

const employees= [
 {id: 0, city: 'New York', wagePerHour: '15'}, 
 {id: 1, city: 'San Francisco', wagePerHour: '18'}, 
 {id: 2, city: 'New York', wagePerHour: '16'}, 
 {id: 3, city: 'Chicago', wagePerHour: '14'}, 
 {id: 4, city: 'Chicago', wagePerHour: '12'}, 
 {id: 5, city: 'San Francisco', wagePerHour: '15'}, 
 {id: 6, city: 'New York', wagePerHour: '18'}, 
 {id: 7, city: 'Los Angeles', wagePerHour: '10'}
];
const cities = employees.reduce((foundValues, nextEmployee) => {
 if(! foundValues.includes(nextEmployee.city)) {
  foundValues.push(nextEmployee.city);
 }
}, []);


1
你的 reduce 函数没有返回任何内容。请注意,如果您还要进行过滤,则 reduce 可能不是最佳方法。 - Dave Newton
6个回答

5
一个更简单的方法是提取所有城市名称,并使用Set函数构建一个唯一的数组:

const employees = [{ id: 0, city: 'New York', wagePerHour: '15' }, { id: 1, city: 'San Francisco', wagePerHour: '18' }, { id: 2, city: 'New York', wagePerHour: '16' }, { id: 3, city: 'Chicago', wagePerHour: '14' }, {  id: 4, city: 'Chicago', wagePerHour: '12' }, { id: 5, city: 'San Francisco', wagePerHour: '15' }, {  id: 6, city: 'New York', wagePerHour: '18' }, { id: 7, city: 'Los Angeles', wagePerHour: '10' }]

let cities = [... new Set(employees.map(x=>x.city))];

console.log(cities);


3

使用Array#reduce方法时,需要返回更新后的previousValue。修复代码最简单的方法是添加return foundValues语句,可以改写为:

const cities = employees.reduce((foundValues, nextEmployee) => 
    foundValues.includes(nextEmployee.city) ? 
    foundValues : foundValues.concat(nextEmployee.city), []
);

然而,你可以自由探索其他更加高效的方法,特别是使用 Array#map[...new Set()]

const employees= [
 {id: 0, city: 'New York', wagePerHour: '15'}, 
 {id: 1, city: 'San Francisco', wagePerHour: '18'}, 
 {id: 2, city: 'New York', wagePerHour: '16'}, 
 {id: 3, city: 'Chicago', wagePerHour: '14'}, 
 {id: 4, city: 'Chicago', wagePerHour: '12'}, 
 {id: 5, city: 'San Francisco', wagePerHour: '15'}, 
 {id: 6, city: 'New York', wagePerHour: '18'}, 
 {id: 7, city: 'Los Angeles', wagePerHour: '10'}
];
const cities = employees.reduce((foundValues, nextEmployee) => {
   if(!foundValues.includes(nextEmployee.city)) {
      foundValues.push(nextEmployee.city);
   }
   return foundValues;
}, []);

console.log( cities );

rewrite

const employees= [
 {id: 0, city: 'New York', wagePerHour: '15'}, 
 {id: 1, city: 'San Francisco', wagePerHour: '18'}, 
 {id: 2, city: 'New York', wagePerHour: '16'}, 
 {id: 3, city: 'Chicago', wagePerHour: '14'}, 
 {id: 4, city: 'Chicago', wagePerHour: '12'}, 
 {id: 5, city: 'San Francisco', wagePerHour: '15'}, 
 {id: 6, city: 'New York', wagePerHour: '18'}, 
 {id: 7, city: 'Los Angeles', wagePerHour: '10'}
];
const cities = employees.reduce((foundValues, nextEmployee) => 
    foundValues.includes(nextEmployee.city) ? 
    foundValues : foundValues.concat(nextEmployee.city), []
);

console.log( cities );


2
你需要返回累加器以供下一次迭代或作为结果。

const
    employees = [{ id: 0, city: 'New York', wagePerHour: '15' }, { id: 1, city: 'San Francisco', wagePerHour: '18' }, { id: 2, city: 'New York', wagePerHour: '16' }, { id: 3, city: 'Chicago', wagePerHour: '14' }, {  id: 4, city: 'Chicago', wagePerHour: '12' }, { id: 5, city: 'San Francisco', wagePerHour: '15' }, {  id: 6, city: 'New York', wagePerHour: '18' }, { id: 7, city: 'Los Angeles', wagePerHour: '10' }],
    cities = employees.reduce((foundValues, nextEmployee) => {
        if (!foundValues.includes(nextEmployee.city)) {
            foundValues.push(nextEmployee.city);
        }
        return foundValues;
    }, []);

console.log(cities);

一个较短的方法是使用映射城市作为构造函数的 Set

const
    employees = [{ id: 0, city: 'New York', wagePerHour: '15' }, { id: 1, city: 'San Francisco', wagePerHour: '18' }, { id: 2, city: 'New York', wagePerHour: '16' }, { id: 3, city: 'Chicago', wagePerHour: '14' }, {  id: 4, city: 'Chicago', wagePerHour: '12' }, { id: 5, city: 'San Francisco', wagePerHour: '15' }, {  id: 6, city: 'New York', wagePerHour: '18' }, { id: 7, city: 'Los Angeles', wagePerHour: '10' }],
    cities = Array.from(new Set(employees.map(({ city }) => city)));

console.log(cities);


2
对数据进行映射以获取城市名称数组,并将它们放入一个集合中以去重,可能是一种更清晰的方法。

const employees=[{id:0,city:"New York",wagePerHour:"15"},{id:1,city:"San Francisco",wagePerHour:"18"},{id:2,city:"New York",wagePerHour:"16"},{id:3,city:"Chicago",wagePerHour:"14"},{id:4,city:"Chicago",wagePerHour:"12"},{id:5,city:"San Francisco",wagePerHour:"15"},{id:6,city:"New York",wagePerHour:"18"},{id:7,city:"Los Angeles",wagePerHour:"10"}];

const cities = new Set(employees.map(obj => obj.city));

console.log([...cities]);

附加文档

1

你可以使用Set

const employees = [
{ id: 0, city: "New York", wagePerHour: "15" },
{ id: 1, city: "San Francisco", wagePerHour: "18" },
{ id: 2, city: "New York", wagePerHour: "16" },
{ id: 3, city: "Chicago", wagePerHour: "14" },
{ id: 4, city: "Chicago", wagePerHour: "12" },
{ id: 5, city: "San Francisco", wagePerHour: "15" },
{ id: 6, city: "New York", wagePerHour: "18" },
{ id: 7, city: "Los Angeles", wagePerHour: "10" },
];

const uniqueCities = [...new Set(employees.map((employee) => employee.city))];    
 console.log(uniqueCities); // [ 'New York', 'San Francisco', 'Chicago', 'Los Angeles' ]

或者你也可以在 JavaScript 中使用对象的特性

const uniqueCities = {};
cities = employees.map((employee) => {
uniqueCities[employee.city] = "";
return;
 });

console.log(Object.keys(uniqueCities )); // [ 'New York', 'San Francisco', 'Chicago', 'Los Angeles' ]

0
已经提供的优秀答案准确地解决了问题。这个答案则通过实现最终目标来偏离那些答案。
最终目标是创建一个柱状图,X轴上显示城市,Y轴上显示每个城市的平均工资。
可以通过将所需逻辑合并到同一次.reduce()迭代中来更快地创建两个单独的数组,一个带有X轴值,另一个带有Y轴值。

// this method directly gets the x-axis and y-axis info required
const getXYaxisData = arr => (
  Object.values(
    arr.reduce(                           // this '.reduce' provides an object
      (fin, {city, wagePerHour}) => ({
        ...fin,
        [city]: {
          city,                           // object has props 'city', 'wagePerHour', 'count'
          wagePerHour: (
            (fin[city]?.wagePerHour ?? 0) +
            +wagePerHour
          ),
          count: (fin[city]?.count ?? 0) + 1
        }
      }),
      {}
    )
  ).map(                                    // this '.map' transforms the 'values' of the object
    ({city, wagePerHour, count}) => ({
      xAxis: city,
      yAxis: (wagePerHour/count).toFixed(2)
    })
  )
);


const employees= [
 {id: 0, city: 'New York', wagePerHour: '15'}, 
 {id: 1, city: 'San Francisco', wagePerHour: '18'}, 
 {id: 2, city: 'New York', wagePerHour: '16'}, 
 {id: 3, city: 'Chicago', wagePerHour: '14'}, 
 {id: 4, city: 'Chicago', wagePerHour: '12'}, 
 {id: 5, city: 'San Francisco', wagePerHour: '15'}, 
 {id: 6, city: 'New York', wagePerHour: '18'}, 
 {id: 7, city: 'Los Angeles', wagePerHour: '10'}
];

const result = getXYaxisData(employees);
// console.log('combined-result: ', result);
console.log('x-axis array: ', result.map(({xAxis}) => xAxis));
console.log('y-axis array: ', result.map(({yAxis}) => yAxis));
.as-console-wrapper { max-height: 100% !important; top: 0 }

上述答案提供了 x 轴和 y 轴的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接