减少,展平和变换嵌套数组

时间:2019-08-15 14:41:56

标签: javascript arrays typescript lodash

我正在尝试找到一种解决方案,以获取嵌套JSON数组的特定格式。我尝试使用 Lodash groupBy Javascript 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. 展开 价格 对象
  4. 数量 移动到 lineitem

有人可以解决吗?

更新1

在按SupplierName成功分组之后,我现在想进一步展平阵列。这样,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
    }
]

3 个答案:

答案 0 :(得分:0)

这应该可以使您获得所需的东西,唯一要注意的是您不能拥有带有多个相同键的对象,因此您需要一个对象数组而不是一个具有多个键的对象之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]

答案 1 :(得分:0)

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,每个属性具有所需结构的对象数组。

这实际上就像遍历所有原始数组并构造正确的对象一样简单。我认为您想念的是如何将它们设置为来自providerName的正确属性名称,而这仅通过检查结果对象是否已经使用Object.keys(obj).includes(key)来完成,以及是否不创建它来完成。只需访问它并将其初始化为一个空数组即可。

答案 2 :(得分:0)

如果您使用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;
}

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