【问题标题】:Group array of objects with object keys使用对象键对对象进行分组
【发布时间】:2021-09-03 07:09:59
【问题描述】:

根据原版 javascript 中的键对对象数组进行分组的最佳方法是什么,假设我有 10000 条记录,这是示例对象

[
 {
  company: "TATA",
  car: "TATA Indica",
  color: "Blue"
 },
 {
  company: "TATA",
  car: "TATA Indica",
  color: "Black"
 },
 {
  company: "TATA",
  car: "Safari",
  color: "Blue"
 },
 {
   "company": "Suzuki",
    car: "",
    color: ""
 }
]

预期的输出是

{
   "company": ["TATA", "Suzuki"],
   "car": ["TATA Indica", "Safari"],
   "color": ["Blue", "Black"]
}

【问题讨论】:

  • 这里的顺序对于companycarcolor 等最终结果数组是否重要?
  • 你应该提供你的尝试
  • 您接受了最慢的版本。 jsben.ch/kLhTZ
  • pilchard 现在有最快的解决方案! jsben.ch/4KKgm

标签: javascript arrays json object data-structures


【解决方案1】:

您可以在此处使用reduce,并对其进行优化,您可以在此处使用Map

const arr = [{
    company: "TATA",
    car: "TATA Indica",
    color: "Blue",
  },
  {
    company: "TATA",
    car: "TATA Indica",
    color: "Black",
  },
  {
    company: "TATA",
    car: "Safari",
    color: "Blue",
  },
  {
    company: "Suzuki",
    car: "",
    color: "",
  },
];

const result = arr.reduce((acc, curr) => {
  Object.keys(curr).forEach((k) => {
    if (curr[k]) {
      if (!acc[k]) acc[k] = new Set();
      else acc[k].add(curr[k]);
    }
  });
  return acc;
}, {});

Object.keys(result).forEach((k) => (result[k] = [...result[k]]));
console.log(result);

【讨论】:

    【解决方案2】:

    对于原始值,您可以轻松地使用SetMap 的组合。 您使用Map 作为键,使用Set 作为值。

    const companies = ["TATA", "Suzuki", "Škoda", ""];
    const cars = ["TATA Indica", "Safari", "Fabia", ""];
    const colors = ["Blue", "Black", "Red", "Yellow", ""]
    const arr = Array.from({length: 1000}, (v, i) => ({
      company: companies[i % companies.length],
      car: cars[i % cars.length],
      color: colors[i % colors.length]
    }));
    
    console.time('Operation');
    const map = new Map();
    for(let item of arr) {
      for(let key of Object.keys(item)){
        let keySet = map.get(key);
        if(!keySet){
          keySet = new Set();
          map.set(key, keySet);
        }
        const value = item[key];
        if(value !== '') {
          keySet.add(item[key]);
        }
      }
    }
    const result = {};
    for(let key of map.keys()) {
      result[key] = Array.from(map.get(key));
    }
    console.timeEnd('Operation');
    console.log(result);

    【讨论】:

      【解决方案3】:

      看起来您使用的数据始终具有稳定的形状。在这种情况下,您可以提前声明结果对象的形状,然后简单地将数据累积到其中,只检查非空值。这里使用MapSet进行累加,然后映射到最终的结果对象。

      const data = [{ company: 'TATA', car: 'TATA Indica', color: 'Blue' }, { company: 'TATA', car: 'TATA Indica', color: 'Black' }, { company: 'TATA', car: 'Safari', color: 'Blue' }, { company: 'Suzuki', car: '', color: '' },];
      
      const map = new Map(Object.keys(data[0]).map((k) => [k, new Set()]));
      
      for (const d of data) {
        for (const k of map.keys()) {
          if (d[k] !== '') {
            map.get(k).add(d[k]);
          }
        }
      }
      
      const result = {};
      for (const k of map.keys()) {
        result[k] = Array.from(map.get(k));
      }
      
      console.log(result);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      奇怪的是,看起来最幼稚的实现实际上证明是相当高效的(根据@Totati's benchmark)。串行map().filter() 调用。

      const data = [{ company: 'TATA', car: 'TATA Indica', color: 'Blue' }, { company: 'TATA', car: 'TATA Indica', color: 'Black' }, { company: 'TATA', car: 'Safari', color: 'Blue' }, { company: 'Suzuki', car: '', color: '' },];
      
      const result = {};
      
      for (const k of Object.keys(data[0])) {
        result[k] = Array.from(
          new Set(data.map(({ [k]: key }) => key).filter((n) => n !== ''))
        );
      }
      
      console.log(result);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

      【解决方案4】:

      您可以使用Set 来存储每个键的唯一值并稍后将它们转换回数组

      const data = [
        {
          company: "TATA",
          car: "TATA Indica",
          color: "Blue",
        },
        {
          company: "TATA",
          car: "TATA Indica",
          color: "Black",
        },
        {
          company: "TATA",
          car: "Safari",
          color: "Blue",
        },
        {
          company: "Suzuki",
          car: "",
          color: "",
        },
      ]
      
      let res = data.reduce((acc, el) => {
        for (const [key, value] of Object.entries(el)) {
          if (!value) continue
      
          if (key in acc) {
            const set = new Set(acc[key])
            set.add(value)
            acc[key] = Array.from(set)
          } else {
            acc[key] = [value]
          }
        }
      
        return acc
      }, {})
      
      console.log(res)

      【讨论】:

      • 嗯,这是最慢的版本。
      猜你喜欢
      • 2019-03-20
      • 1970-01-01
      • 2021-05-04
      • 2021-04-12
      • 2022-01-08
      • 2022-01-14
      相关资源
      最近更新 更多