【问题标题】:Reduce, flatten and transform nested array减少、展平和变换嵌套数组
【发布时间】:2019-12-21 23:57:09
【问题描述】:

我正在尝试找到一种解决方案来为我的嵌套 JSON 数组获取特定格式。我曾尝试使用 Lodash groupByJavascript reduce 但我似乎找不到解决方案。

输入格式:

[
  { 
     lineitem: {
        id:1,
        price: { 
            amount:100
        },
        supplierName:TestSupplier1
     },
     quantity:10
  }, 
  {
     lineitem: {
        id:2,
        price: { 
            amount:200
        },
        supplierName:TestSupplier2
    },
    quantity:20
  },
  { 
     lineitem: {
        id:3,
        price: { 
            amount:300
        },
        supplierName:TestSupplier1
     },
     quantity:30
  }, 
  {
     lineitem: {
        id:4,
        price: { 
            amount:400
        },
        supplierName:TestSupplier4
    },
    quantity:40
  },
]

所需的输出格式:

[
  { 
     TestSupplier1: [
        {
           id:1,               
           amount:100,
           quantity:10
        },
        {
           id:3,
           amount:300,              
           quantity:30            
        }
     ],
     TestSupplier2: [
        {
           id:2,
           amount:200,               
           quantity:20    
        }
     ],
     TestSupplier4: [
        {
          id:4,              
          amount:400,
          quantity:40
        }
     ]
]

我认为这里有 3 个步骤:

  1. supplierName分组
  2. 扁平化价格对象
  3. quantity 移动到 lineitem

谁能帮忙解决这个问题?

更新 1

在按供应商名称成功分组后,我现在想进一步展平数组。这样 TestSupplier'X' 被放置在每个数组中。

请看下面的例子:

[
    {
       supplierName:TestSupplier1,
       id:1,               
       amount:100,
       quantity:10
    },
    {   
       supplierName:TestSupplier1,
       id:3,
       amount:300,              
       quantity:30            
    },
    {
       supplierName:TestSupplier2,
       id:2,
       amount:200,               
       quantity:20    
    },
    {
       supplierName:TestSupplier4,
       id:4,              
       amount:400,
       quantity:40
    }
]

【问题讨论】:

  • 在您的输出对象中,TestSupplier1 有 2 个具有相同名称“lineitem”的属性,这是不可能的。如果我将 TestSupplier1 设为数组而不是对象可以吗?
  • 请包括您的尝试;您可能会偏离一点点,很遗憾有人已经花时间从头开始制定答案,而他们可能只能调整您尝试的一行...

标签: javascript arrays typescript lodash


【解决方案1】:

如果您使用 TypeScript,以下内容可能会有所帮助:

interface IInput {
  lineitem: {
    id: number;
    price: {
      amount: number;
    }
    supplierName: string;
  }
  quantity: number;
}

interface IOutputA {
  [key: string]: {
    id: number;
    amount: number;
    quantity: number;
  }[];
}

interface IOutputB {
  supplierName: string;
  id: number;
  amount: number;
  quantity: number;
}

function transformA(input: IInput[]): IOutputA {
  const ret: IOutputA = {};
  input.forEach(it => {
    ret[it.lineitem.supplierName] = [];
    ret[it.lineitem.supplierName].push({
      id: it.lineitem.id,
      amount: it.lineitem.price.amount,
      quantity: it.quantity,
    }
  }
  return ret;
}

function transformB(outputA: IOutputA): IOutputB {
  const ret: IOutputB = [];
  Object.keys(outputA).forEach(x => {
    outputA[x].forEach(y => {
      ret.push({
        supplierName: x,
        id: y.id,
        amount: y.amount,
        quantity: y.quantity,
      });
    });
  });
  return ret;
}

很高兴看到您也尝试解决这个问题。

【讨论】:

    【解决方案2】:
    let resObj = {};
    data.forEach( el => {
        if(!Object.keys(resObj).includes(el.lineitem.supplierName))
        {
            console.log(el);
            resObj[el.lineitem.supplierName] = [];
            }
        let newInnerObj = { id: el.lineitem.id, amount: el.lineitem.price.amount, quantity: el.quantity };
        resObj[el.lineitem.supplierName].push(newInnerObj);
    });
    
    console.log(resObj);
    

    这是一个简单的答案,但就像我在评论中所说的那样 - 您不能拥有具有相同名称属性的对象,因此结果是一个具有 TestSupplierX 作为属性的对象,并且每个属性都是一个数组具有您要求的结构的对象。

    这真的就像遍历所有原始数组并构造正确的对象一样简单。我认为您错过的是如何将它们放入来自供应商名称的正确属性名称中,这只是通过检查结果对象是否已经使用Object.keys(obj).includes(key) 来完成,如果没有,只需通过访问它并将其初始化为一个空数组。

    【讨论】:

    • 感谢您提出的解决方案。我将如何绕过然后展平阵列以使其不嵌套?阿卡。将 TestSupplierX 移动到每个数组中。 (更新了我的问题以反映情况)
    【解决方案3】:

    这应该可以满足您的需求,唯一需要注意的是,您不能拥有具有多个相同键的对象,因此您拥有对象数组而不是具有多个键的对象lineItem:

    const result = data.reduce((result, item) => {
      // Get the supplier name, id, amount and quantity of the current item
      const supplierName = item.lineitem.supplierName;
    
      const {
        id,
        price: { amount }
      } = item.lineitem;
      const { quantity } = item;
    
      const lineItem = {
        id,
        amount,
        quantity
      };
    
      // If it already exists in the result, add the data to the existing key
      if (Object.keys(result).includes(supplierName)) {
        return Object.assign({}, result, {
          [supplierName]: [...result[supplierName], lineItem]
        });
      } else {
        // Otherwise create a new key
        return Object.assign({}, result, { [supplierName]: [lineItem] });
      }
    }, {});
    

    这给了你:

    { TestSupplier1:
       [ { id: 1, amount: 100, quantity: 10 },
         { id: 3, amount: 300, quantity: 30 } ],
      TestSupplier2: [ { id: 2, amount: 200, quantity: 20 } ],
      TestSupplier4: [ { id: 4, amount: 400, quantity: 40 } ] }
    

    在最初的问题中,您要求将整个内容包装在一个数组中,这显然就像[result] 一样简单。

    【讨论】:

    • 感谢您提出的解决方案。我将如何绕过然后展平阵列以使其不嵌套?阿卡。将 TestSupplierX 移动到每个数组中。 (更新了我的问题以反映情况)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 2014-05-28
    • 1970-01-01
    • 2015-03-14
    相关资源
    最近更新 更多