【问题标题】:Skip JSON.map() for the subsequent elements为后续元素跳过 JSON.map()
【发布时间】:2026-01-27 09:35:01
【问题描述】:

DEMO (请检查浏览器控制台的输出)

我有一个 JSON customerItemResponse 格式

{
    "totalResults": someNumber,
    "results": [
        {
            "totalItem": 406,
            "customerId": "10000"
        },
        {
            "totalItem": 468,
            "customerId": "10001"
        },
        {
            "totalItem": 20,
            "customerId": "10002"
        },
...

然后我有另一个 JSON customerInfo:

{
    "totalResults": someNumber,
    "results": [
        {
            "customerId": "10000",
            "region": "4",
            "area": "42",
        },
        {
            "customerId": "10001",
            "region": "4",
            "area": "43",
        },
        {
            "customerId": "10002",
            "region": "5",
            "area": "52",
        },

现在我必须创建一个格式的 JSON

[
    {
        region:'4'
        regionDetails:[
                          {
                              area:'42'
                              customerDetails:[
                                              {
                                                   customerId:'10000'
                                                   totalItem:406 
                                              },
                                              {
                                                   customerId:'10005'
                                                   totalItem:301 
                                              },
                                              ]
                          },
                          {
                              area:'11'
                              customerDetails:[
                                              {
                                                   customerId:'10010'
                                                   totalItem:11 
                                              },
                                              {
                                                   customerId:'10021'
                                                   totalItem:105 
                                              },
                                              ]
                          },
                      ]
    },
    {
        region:'5'
        regionDetails:[
                          {
                              area:'52'
                              customerDetails:[
                                              {
                                                   customerId:'10002'
                                                   totalItem:52 
                                              },
                                              {
                                                   customerId:'10027'
                                                   totalItem:310 
                                              },
                                              ]
                          },
                          {
                              area:'41'
                              customerDetails:[
                                              {
                                                   customerId:'10017'
                                                   totalItem:109 
                                              },
                                              {
                                                   customerId:'10041'
                                                   totalItem:450 
                                              },
                                              ]
                          },
                      ]
    }

]

这是我写的逻辑:

customerData=<CustomerDataInterface[]>[]

mapJson() {
        this.customerItemResponse.map((res, index) => {
            this.customerInfo.find((obj) => {
                if (obj.customerId == res.customerId) {
                    this.customerData.length
                        ? this.customerData.map((data, index1) => {
                              if (data.region == obj.region) {
                                  data.regionDetails.length
                                      ? data.regionDetails.map((regDetails, index2) => {
                                            if (regDetails.area == obj.area) {
                                                regDetails.dealerDetails.push({
                                                    customerId: obj.customerId,
                                                    totalItem: res.totalItem,
                                                });
                                                return;
                                            }
                                            if (index2 == data.regionDetails.length - 1) {
                                                data.regionDetails.push({ area: obj.area, dealerDetails: [] });
                                            }
                                        })
                                      : data.regionDetails.push({ area: obj.area, dealerDetails: [] });
                                  return;
                              }
                              if (index1 == this.customerData.length - 1) {
                                  this.customerData.push({ region: obj.region, regionDetails: [] });
                              }
                          })
                        : this.customerData.push({ region: obj.region, regionDetails: [] });
                }
            });
        });
        console.log(this.customerData);
    }

现在控制台的输出有几个region重复了。假设我有6 唯一的regionthis.customerData.length31

我认为return; 没有按预期工作。并且不会跳过后续元素。

【问题讨论】:

  • 区号是唯一的吗? region 1 和 2 都可以有 area: '11' 吗?
  • Area 是独一无二的。如果region 1 有area 11,则其他region 不会有它。
  • 仅供参考,.map 的目的是转换/返回数据。实际上,您似乎将其视为.forEach,这可能会让其他阅读您的代码的人感到困惑。

标签: javascript arrays json angular typescript


【解决方案1】:

这是使用 js 地图解决问题的有效方法。我们可以使用有关相应区域和区域的信息构建地图。并且在将数据构建到地图之后 - 将其转换回简单的 js 结构,例如对象和数组

mapJson() {
    const customerToTotalMap = new Map(this.customerItemResponse.map(({customerId, totalItem}) => [customerId, totalItem]));
    const regionsMap = new Map();
    for(let {customerId, region, area} of this.customerInfo) {
      let regionAreas;
      if(regionsMap.has(region)) {
        regionAreas = regionsMap.get(region);
      } else {
        regionAreas = new Map();
        regionsMap.set(region, regionAreas);
      }
      
      let areaInfo;
      if(regionAreas.has(area)) {
        areaInfo = regionAreas.get(area);
      } else {
        areaInfo = [];
        regionAreas.set(area, areaInfo);
      }
      areaInfo.push({customerId, totalItem: customerToTotalMap.get(customerId)});
    }
    this.customerData = [...regionsMap.entries()].map(([region, areas]) => ({
      region,
      regionDetails: [...areas.entries()].map(([area, customerDetails]) => ({
        area,
        customerDetails
      }))
    }))
    console.log(this.customerData);
}

【讨论】:

  • 但是既然可以通过迭代一次来完成数组,为什么还要迭代两次呢?
  • @Naman 他们在哪里迭代数组两次?
  • customerToTotalMap 已经迭代了一次。
  • @Naman 这个解决方案是 O(n + m),其中 n 是 customerItemResponse 的长度,m 是 customerInfo 的长度,而你的解决方案是 O(n * m * n) 我猜这要复杂得多
  • 那是为了映射customerId -&gt; totalItem。第二个循环是为customerInfo 数组创建区域和区域特定映射
【解决方案2】:

这类似于@Andrei 的回答。它创建一个对象文字作为映射器。此外,它在创建区域和区域时使用它们之间的映射。所以,最后你可以直接获取 regionMapper 对象的值,而无需再次通过映射器对象

const customerItemResponse=[{customerId:10000,totalItem:77},{customerId:10001,totalItem:37},{customerId:10002,totalItem:295},{customerId:10003,totalItem:458},{customerId:10004,totalItem:248},{customerId:10005,totalItem:35},{customerId:10006,totalItem:280},{customerId:10007,totalItem:147},{customerId:10008,totalItem:439},{customerId:10009,totalItem:401},{customerId:10010,totalItem:489},{customerId:10011,totalItem:414},{customerId:10012,totalItem:287},{customerId:10013,totalItem:391},{customerId:10014,totalItem:125},{customerId:10015,totalItem:207},{customerId:10016,totalItem:197},{customerId:10017,totalItem:151},{customerId:10018,totalItem:225},{customerId:10019,totalItem:333},{customerId:10020,totalItem:361},{customerId:10021,totalItem:225},{customerId:10022,totalItem:242},{customerId:10023,totalItem:150},{customerId:10024,totalItem:52},{customerId:10025,totalItem:475},{customerId:10026,totalItem:494},{customerId:10027,totalItem:30},{customerId:10028,totalItem:189},{customerId:10029,totalItem:112},{customerId:10030,totalItem:482},{customerId:10031,totalItem:283},{customerId:10032,totalItem:159},{customerId:10033,totalItem:440},{customerId:10034,totalItem:461},{customerId:10035,totalItem:76},{customerId:10036,totalItem:84},{customerId:10037,totalItem:392},{customerId:10038,totalItem:296},{customerId:10039,totalItem:293},{customerId:10040,totalItem:135},{customerId:10041,totalItem:348},{customerId:10042,totalItem:338},{customerId:10043,totalItem:444},{customerId:10044,totalItem:15},{customerId:10045,totalItem:32},{customerId:10046,totalItem:67},{customerId:10047,totalItem:277},{customerId:10048,totalItem:65},{customerId:10049,totalItem:95},{customerId:10050,totalItem:290}],
  customerInfo=[{customerId:10000,region:"3",area:"32"},{customerId:10001,region:"2",area:"22"},{customerId:10002,region:"2",area:"25"},{customerId:10003,region:"3",area:"31"},{customerId:10004,region:"2",area:"25"},{customerId:10005,region:"1",area:"11"},{customerId:10006,region:"1",area:"14"},{customerId:10007,region:"5",area:"55"},{customerId:10008,region:"5",area:"51"},{customerId:10009,region:"4",area:"45"},{customerId:10010,region:"1",area:"14"},{customerId:10011,region:"1",area:"12"},{customerId:10012,region:"3",area:"33"},{customerId:10013,region:"2",area:"25"},{customerId:10014,region:"4",area:"41"},{customerId:10015,region:"3",area:"32"},{customerId:10016,region:"5",area:"55"},{customerId:10017,region:"2",area:"23"},{customerId:10018,region:"3",area:"33"},{customerId:10019,region:"5",area:"51"},{customerId:10020,region:"4",area:"42"},{customerId:10021,region:"1",area:"12"},{customerId:10022,region:"1",area:"14"},{customerId:10023,region:"1",area:"14"},{customerId:10024,region:"1",area:"13"},{customerId:10025,region:"4",area:"45"},{customerId:10026,region:"3",area:"34"},{customerId:10027,region:"2",area:"24"},{customerId:10028,region:"4",area:"45"},{customerId:10029,region:"2",area:"22"},{customerId:10030,region:"2",area:"22"},{customerId:10031,region:"2",area:"21"},{customerId:10032,region:"3",area:"33"},{customerId:10033,region:"1",area:"11"},{customerId:10034,region:"3",area:"33"},{customerId:10035,region:"3",area:"32"},{customerId:10036,region:"2",area:"22"},{customerId:10037,region:"4",area:"41"},{customerId:10038,region:"3",area:"31"},{customerId:10039,region:"5",area:"51"},{customerId:10040,region:"2",area:"23"},{customerId:10041,region:"4",area:"45"},{customerId:10042,region:"1",area:"14"},{customerId:10043,region:"5",area:"54"},{customerId:10044,region:"3",area:"34"},{customerId:10045,region:"5",area:"51"},{customerId:10046,region:"4",area:"42"},{customerId:10047,region:"5",area:"53"},{customerId:10048,region:"1",area:"11"},{customerId:10049,region:"3",area:"35"},{customerId:10050,region:"5",area:"51"}];
  
const customerItemMapper = {}

for (const c of customerItemResponse)
  customerItemMapper[c.customerId] = c.totalItem

const regionMapper = {},
      areaMapper = {};

for (const { customerId, region, area } of customerInfo) {
  let regionKey = `Region_${region}`,
      areaKey = `Area_${area}`,
      totalItem = customerItemMapper[customerId];

  if (!(regionKey in regionMapper))
    regionMapper[regionKey] = { region, regionDetails: [] }

  if (!(areaKey in areaMapper)) {
    const o = { area, customerDetails: [] }
    areaMapper[areaKey] = o;
    regionMapper[regionKey].regionDetails.push(o) // area-region relation
  }

  areaMapper[areaKey].customerDetails.push({ customerId, totalItem })
}

console.log(Object.values(regionMapper))

【讨论】:

  • 还有一件事。如何根据totalItemareaMapper 值进行排序?
  • 同意,结果是一样的。唯一的问题是:我认为 js 对象在长数据集上的性能不是很好。
  • @Naman 您可以在处理 customerItemResponse 数组之前对其进行排序 customerItemResponse.sort((a,b) =&gt; a.totalItem - b.totalItem)