【问题标题】:Array.reduce() group by object field and extend all other fields to their corresponding grouped object fieldArray.reduce() 按对象字段分组并将所有其他字段扩展到其相应的分组对象字段
【发布时间】:2019-11-08 09:55:32
【问题描述】:

我想为一个对象创建一个 group-By 函数,在其中我按一个字段对数组进行分组,然后通过相应的 group-object 字段从数组中“强制”即将到来的文档的所有字段。

const groupInDoc = (array, fieldname) => {
    let groupedResultDoc = array.reduce((carDocs, current) => {  
        let keyCount = Object.keys(current).length;
        let obj = {};
        for (let [key, value] of Object.entries(current)) { 
            console.log(`${key}: ${value}`);           

            //check if key is same as the fieldname to group-by.
            if (key == fieldname) {
            } else {
                obj[key] = value;
            }

        }      
        if (carDocs.hasOwnProperty(current[fieldname])) {
            //if (Array.isArray(carDocs[current[fieldname]])){
            carDocs[current[fieldname]] = obj;
            //}                                
        } else {            
            carDocs[current[fieldname]] =  obj;

        }  
        return carDocs;     
    }, Object.create({}));

    return groupedResultDoc;
}

我现在有一个问题,如何通过数组对象中的其他相应对象字段来扩展分组对象的字段?

例如,如果我的分组对象有一个包含字段数组和字段“字符串”的组键的子文档,那么我想将匹配组对象中的所有新数组值推送到旧数组中,并且我还想将字符串与“+”一起强制...我该怎么做?

编辑:我的原始数据:

let doc = [
    {
        "car": "Ford",
        "prices": ["12", "3", "5", "1"],
        "model": "SUV"
    },
    {
        "car": "Ford",
        "prices": ["99","88","77"],
        "model": "T3"
    },
    {
        "car": "Toyota",
        "prices": ["33","44","55"],
        "model": "Subaru"
    },
    {
        "car": "Toyota",
        "prices": ["66", "50", "22"],
        "model": "Cheyenne"
    },
    {
        "car": "Peugeot",
        "prices": ["1","2","3"],
        "model" : "503"
    }
];

我的结果是:

CarDocs:  { Ford: { prices: [ '99', '88', '77' ], model: 'T3' },
  Toyota: { prices: [ '66', '50', '22' ], model: 'Cheyenne' },
  Peugeot: { prices: [ '1', '2', '3' ], model: '503' } }

但应该是:

CarDocs:  { Ford: { prices: ["12", "3", "5", "1", '99', '88', '77' ], model: 'T3', 'SUV' },
  Toyota: { prices: [33","44","55", '66', '50', '22' ], model: 'Cheyenne', 'Subaru' },
  Peugeot: { prices: [ '1', '2', '3' ], model: '503' } }

【问题讨论】:

  • 你能发布你的原始数据吗?我的意思是初始数组
  • 是的,抱歉,我在原帖中添加了它
  • model 在这里必须是一个数组或单个字符串。

标签: javascript arrays ecmascript-6 group-by document


【解决方案1】:

您需要将值与以前的值合并,而在您的代码中,您在每次迭代中分配新值

let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let final = doc.reduce((op,{car,prices,model:m})=>{
  op[car] = op[car] || {prices:[],model:[]}
  op[car].prices = [...op[car].prices, ...prices]
  op[car].model = [...op[car].model, m]
  return op
},{})

console.log(final)

【讨论】:

    【解决方案2】:

    您可以根据每个循环上的键名使用 reduce 合并每个对象:

    let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];
    
    let CarDoc = doc.reduce((a, {car, prices, model}) => {
      if(a[car]) {
        prices.forEach(p => a[car].prices.push(p))
        a[car].model = [...a[car].model, model]
      } else {
        a[car] = {prices, model:[model]}
      }
      return a
    }, {})
    
    console.log(CarDoc)

    可读性较差的单行版本:

    let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];
    
    let CarDoc = doc.reduce((a, {car, prices, model}) => a[car] ? {...a, [car]: {prices: a[car].prices.concat(prices), model: a[car].model.concat(model)}} : {...a, [car]: {prices, model:[model]}}, {})
    
    console.log(CarDoc)

    编辑:

    let doc = [{"car": "Ford", test: 'test', "prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford", test: 'test', "prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];
    
    let CarDoc = doc.reduce((a, {car, ...rest}) => {
      Object.entries(rest).forEach(([k,v]) => {
        if(a[car]) {
          a[car][k] = [...a[car][k] || [], v]
        } else {
          a[car] = {...a[car], [k]: [v]}
        }
      })
      
      return a
    }, {})
    
    console.log(CarDoc)

    【讨论】:

    • 谢谢,但有没有办法概括代码,使其适用于所有字段和字段类型?我必须检查该字段是什么类型的字段吗?
    • 你可以,但是是的,你必须适应这种类型。我认为当您合并价格时,合并时最好采用[[1,2,3],[4,5,6]] 之类的格式,以便您可以通过索引访问相关值。所以,你可以把所有的东西都放在一个数组中,每次都将值推送到对应的数组中。
    • 很好,。这给我留下了深刻的印象(在代码行中)我尝试了几个小时来让它正确,但我明白了,但要复杂得多,你能解释一下你在哪里学到的吗? a[car][k] = [...a[car][k] || [], v] 是做什么的?我知道如果它不存在,它会即时创建键 a[car][k],但是 [...a[car][k] || [], v] 创建一个值为 a[car][k] 的数组,其中一个空数组作为后备,还是值本身?这是什么意思?
    • 你说得对,... 会将所有现有属性展开,但如果没有任何属性,则会回退到一个空数组。
    • ok thx,作为一个初学者,我很难找到这样一个干净紧凑的解决方案..
    【解决方案3】:

    无耻的插头。我的库blinq 提供了许多使这种转换变得容易的函数:

    const result = blinq(doc)
      .groupBy(c => c.car)
      .select(g => ({
        car: g.key,
        prices: g
          .selectMany(c => c.prices)
          .distinct()
          .toArray(),
        models: g.select(c => c.model).toArray()
      }))
      .toArray();
    

    const doc = [{
        "car": "Ford",
        "prices": ["12", "3", "5", "1"],
        "model": "SUV"
      },
      {
        "car": "Ford",
        "prices": ["99", "88", "77"],
        "model": "T3"
      },
      {
        "car": "Toyota",
        "prices": ["33", "44", "55"],
        "model": "Subaru"
      },
      {
        "car": "Toyota",
        "prices": ["66", "50", "22"],
        "model": "Cheyenne"
      },
      {
        "car": "Peugeot",
        "prices": ["1", "2", "3"],
        "model": "503"
      }
    ];
    
    const {
      blinq
    } = window.blinq
    
    const result = blinq(doc)
      .groupBy(c => c.car)
      .select(g => ({
        car: g.key,
        prices: g
          .selectMany(c => c.prices)
          .distinct()
          .toArray(),
        models: g.select(c => c.model).toArray()
      }))
      .toArray();
    console.log(result)
    <script src="https://cdn.jsdelivr.net/npm/blinq"></script>

    【讨论】:

    • 不会撒谎,这会让事情看起来很多更难阅读。不过图书馆不错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    相关资源
    最近更新 更多