简体   繁体   English

如何使用纯Javascript访问最深层的双重嵌套数组/对象?

[英]How to access innermost levels of doubly nested arrays/objects using plain Javascript?

I suspect the answer is simple but I've searched this site and others and haven't found one. 我怀疑答案很简单,但是我搜索了该网站和其他网站,但没有找到一个。 I have a doubly nested data structure and can't figure out how to iterate over the innermost levels. 我有一个双重嵌套的数据结构,无法弄清楚如何在最内层进行迭代。 I'm guessing it might involve the forEach() or map() method but nothing I've tried works. 我猜想它可能涉及到forEach()或map()方法,但我尝试过的任何方法都没有。

Background: I've simplified the data for this question. 背景:我已经简化了该问题的数据。 The data (pasted below) are stored in an array containing 2 retail store objects. 数据(粘贴在下面)存储在包含2个零售商店对象的数组中。 Each store object has a visits property whose value is an array of visit objects. 每个商店对象都有一个visits属性,其值是一组visit对象。 Each visit (object) is identified by a visit date (assume there can be at most 1 visit to store A on date B). 每次访问(对象)都由访问日期标识(假设在日期B最多可以有1次访问存储A)。 Each visit object contains a values property whose value is an array of transactions (purchases or returns) made at the visit. 每个访问对象都包含一个values属性,其值是该访问时进行的交易(购买或退货)数组。 In the actual full data, the number of transactions per date per store is highly variable. 在实际的完整数据中,每个商店的每个日期的交易数量变化很大。

Tasks I need help with: (a) rename property key to visitDate , (b) rename property values to transactions , (c) delete the 8 redundant properties (from storeID to storeVisitDate ) but retain the action and dollarAmount properties, and (d) rename property dollarAmount to dollars . 我需要帮助的任务:(a)将属性key重命名为visitDate ,(b)将属性values重命名为transactions ,(c)删除8个冗余属性(从storeIDstoreVisitDate ),但保留actiondollarAmount属性,以及(d)将属性dollarAmount重命名为dollars

Any help would be most appreciated. 非常感激任何的帮助。 Thanks. 谢谢。

 [
   {
     "storeName": "Ye Olde Candy Shoppe",
     "address": "1313 Vampire Lane, Cityville NY 99999",
     "zipCode": "99999",
     "storeSize": "large",
     "visits": [
       {
         "key": "5/3/12",
         "values": [
           {
             "storeID": "53454447",
             "storeName": "Ye Olde Candy Shoppe",
             "city": "Cityville",
             "building": "1313",
             "street": "Vampire Lane",
             "zipcode": "99999",
             "storeSize": "large",
             "storeVisitDate": "5/3/12",
             "action": "Return",
             "dollarAmount": "65.43"
           },
           {
             "storeID": "53454447",
             "storeName": "Ye Olde Candy Shoppe",
             "city": "Cityville",
             "building": "1313",
             "street": "Vampire Lane",
             "zipcode": "99999",
             "storeSize": "large",
             "storeVisitDate": "5/3/12",
             "action": "Purchase",
             "dollarAmount": "12.43"
           },
           {
             "storeID": "53454447",
             "storeName": "Ye Olde Candy Shoppe",
             "city": "Cityville",
             "building": "1313",
             "street": "Vampire Lane",
             "zipcode": "99999",
             "storeSize": "large",
             "storeVisitDate": "5/3/12",
             "action": "Purchase",
             "dollarAmount": "5.43"
           }
         ]
       },
       {
         "key": "12/31/12",
         "values": [
           {
             "storeID": "53454447",
             "storeName": "Ye Olde Candy Shoppe",
             "city": "Cityville",
             "building": "1313",
             "street": "Vampire Lane",
             "zipcode": "99999",
             "storeSize": "large",
             "storeVisitDate": "12/31/12",
             "action": "Purchase",
             "dollarAmount": "2.53"
           }
         ]
       },
       {
         "key": "1/24/13",
         "values": [
           {
             "storeID": "53454447",
             "storeName": "Ye Olde Candy Shoppe",
             "city": "Cityville",
             "building": "1313",
             "street": "Vampire Lane",
             "zipcode": "99999",
             "storeSize": "large",
             "storeVisitDate": "1/24/13",
             "action": "Return",
             "dollarAmount": "2.53"
           },
           {
             "storeID": "53454447",
             "storeName": "Ye Olde Candy Shoppe",
             "city": "Cityville",
             "building": "1313",
             "street": "Vampire Lane",
             "zipcode": "99999",
             "storeSize": "large",
             "storeVisitDate": "1/24/13",
             "action": "Return",
             "dollarAmount": "64.22"
           }
         ]
       }
     ]
   },
   {
     "storeName": "Mike's Bikes",
     "address": "2626 Aardvark Circle, Townsville NY 88888",
     "zipCode": "88888",
     "storeSize": "small",
     "visits": [
       {
         "key": "8/8/14",
         "values": [
           {
             "storeID": "24335234",
             "storeName": "Mike's Bikes",
             "city": "Townsville",
             "building": "2626",
             "street": "Aardvark Circle",
             "zipcode": "88888",
             "storeSize": "small",
             "storeVisitDate": "8/8/14",
             "action": "Purchase",
             "dollarAmount": "443.55"
           },
           {
             "storeID": "24335234",
             "storeName": "Mike's Bikes",
             "city": "Townsville",
             "building": "2626",
             "street": "Aardvark Circle",
             "zipcode": "88888",
             "storeSize": "small",
             "storeVisitDate": "8/8/14",
             "action": "Purchase",
             "dollarAmount": "34"
           },
           {
             "storeID": "24335234",
             "storeName": "Mike's Bikes",
             "city": "Townsville",
             "building": "2626",
             "street": "Aardvark Circle",
             "zipcode": "88888",
             "storeSize": "small",
             "storeVisitDate": "8/8/14",
             "action": "Purchase",
             "dollarAmount": "12.32"
           }
         ]
       },
       {
         "key": "10/3/15",
         "values": [
           {
             "storeID": "24335234",
             "storeName": "Mike's Bikes",
             "city": "Townsville",
             "building": "2626",
             "street": "Aardvark Circle",
             "zipcode": "88888",
             "storeSize": "small",
             "storeVisitDate": "10/3/15",
             "action": "Purchase",
             "dollarAmount": "233.1"
           },
           {
             "storeID": "24335234",
             "storeName": "Mike's Bikes",
             "city": "Townsville",
             "building": "2626",
             "street": "Aardvark Circle",
             "zipcode": "88888",
             "storeSize": "small",
             "storeVisitDate": "10/3/15",
             "action": "Return",
             "dollarAmount": "44.99"
           }
         ]
       }
     ]
   }
 ]

You're correct! 没错! You can do most of this with .map(). 您可以使用.map()完成大部分操作。 And the new ES6 standard makes a lot of this much easier, and with the below function you wont even modify any of the original data!: 新的ES6标准使这一切变得更加容易,并且使用以下功能,您甚至都不会修改任何原始数据!:

array.map(store => {
  //return a new object that takes all the store info, then reassigns the visits key in a new object
  return Object.assign({}, store, {
    //map over visits, and reassign the key key to visitDate
    visits: store.visits.map(({ key: visitDate, values }) => {
      return {
        //return an obj with visit date
        visitDate,
        // do destructuring again to create objects of action,dollars
        transactions: values.map(({ action, dollarAmount: dollars }) => ({ action, dollars }))
      };
    })
  });
});

( working example on jsFiddle here - just open JS console to see the converted data set) 此处是jsFiddle上的工作示例 -只需打开JS控制台即可查看转换后的数据集)

Few points about solution below: 以下是有关解决方案的几点说明:

  • it'll work even if your data has more keys that in a sample you pasted (you mentioned that this is a simplified set, so it might be important) 即使您的数据有更多的键(在您粘贴的样本中)也可以使用(您提到这是一个简化的集合,因此可能很重要)
  • it uses "map" a lot, instead of manually iterating over arrays. 它使用“映射”很多,而不是手动遍历数组。 I find it more readable. 我发现它更具可读性。

     // Go over all stores stores.map(function(store) { // In each store, go over all visits. store.visits.map(function(visit) { // In each visit, copy 'key' to 'visitDate' // and 'values' to 'transactions'. // Then delete old names ('key' and 'values'). visit.visitDate = visit.key; visit.transactions = visit.values; delete visit.key; delete visit.values; // For each transaction, replace it with a simple // map with only 'action' and 'dollars'. visit.transactions = visit.transactions.map(function(tx) { return { action: tx.action, dollars: tx.dollarAmount }; }); }); }); 

Note that map() is supported in IE9 and newer. 请注意,在IE9和更高版本中支持map()

To rename properties, you can create a new one with the same value then delete the old one. 要重命名属性,您可以创建一个具有相同值的新属性,然后delete旧属性。

You can use this for all parts, but looking at your structure, it looks neater to combine b,c,d together by using map() to create a new array of "optimised" transactions and assigning that to the new transactions property. 您可以将其用于所有部分,但是在您的结构上,通过使用map()创建新的“优化”交易并将其分配给新的transactions属性,将b,c,d组合在一起看起来更加巧妙。

 // (I put this in a function so the logic can be at the top of the snippet) function fixData(stores) { // loop stores and their visits for (var iStore = 0; iStore < stores.length; iStore++) { var store = stores[iStore]; for (var iVisit = 0; iVisit < store.visits.length; iVisit++) { var visit = store.visits[iVisit]; // (a) rename property key to visitDate // add a new property with the same value then delete the old property visit.visitDate = visit.key; delete visit.key; // (b) rename property values to transactions // add a new property with the same value then delete the old property // (c) delete the 8 redundant properties (from storeID to storeVisitDate) // we could delete keys but quicker to map a new object // (d) rename property dollarAmount to dollars. // just give the new object property a different name visit.transactions = visit.values.map(function(trans) { return { action: trans.action, dollars: trans.dollarAmount } }); delete visit.values; } } console.log(stores); } var stores = [{ "storeName": "Ye Olde Candy Shoppe", "address": "1313 Vampire Lane, Cityville NY 99999", "zipCode": "99999", "storeSize": "large", "visits": [{ "key": "5/3/12", "values": [{ "storeID": "53454447", "storeName": "Ye Olde Candy Shoppe", "city": "Cityville", "building": "1313", "street": "Vampire Lane", "zipcode": "99999", "storeSize": "large", "storeVisitDate": "5/3/12", "action": "Return", "dollarAmount": "65.43" }, { "storeID": "53454447", "storeName": "Ye Olde Candy Shoppe", "city": "Cityville", "building": "1313", "street": "Vampire Lane", "zipcode": "99999", "storeSize": "large", "storeVisitDate": "5/3/12", "action": "Purchase", "dollarAmount": "12.43" }, { "storeID": "53454447", "storeName": "Ye Olde Candy Shoppe", "city": "Cityville", "building": "1313", "street": "Vampire Lane", "zipcode": "99999", "storeSize": "large", "storeVisitDate": "5/3/12", "action": "Purchase", "dollarAmount": "5.43" }] }, { "key": "12/31/12", "values": [{ "storeID": "53454447", "storeName": "Ye Olde Candy Shoppe", "city": "Cityville", "building": "1313", "street": "Vampire Lane", "zipcode": "99999", "storeSize": "large", "storeVisitDate": "12/31/12", "action": "Purchase", "dollarAmount": "2.53" }] }, { "key": "1/24/13", "values": [{ "storeID": "53454447", "storeName": "Ye Olde Candy Shoppe", "city": "Cityville", "building": "1313", "street": "Vampire Lane", "zipcode": "99999", "storeSize": "large", "storeVisitDate": "1/24/13", "action": "Return", "dollarAmount": "2.53" }, { "storeID": "53454447", "storeName": "Ye Olde Candy Shoppe", "city": "Cityville", "building": "1313", "street": "Vampire Lane", "zipcode": "99999", "storeSize": "large", "storeVisitDate": "1/24/13", "action": "Return", "dollarAmount": "64.22" }] }] }, { "storeName": "Mike's Bikes", "address": "2626 Aardvark Circle, Townsville NY 88888", "zipCode": "88888", "storeSize": "small", "visits": [{ "key": "8/8/14", "values": [{ "storeID": "24335234", "storeName": "Mike's Bikes", "city": "Townsville", "building": "2626", "street": "Aardvark Circle", "zipcode": "88888", "storeSize": "small", "storeVisitDate": "8/8/14", "action": "Purchase", "dollarAmount": "443.55" }, { "storeID": "24335234", "storeName": "Mike's Bikes", "city": "Townsville", "building": "2626", "street": "Aardvark Circle", "zipcode": "88888", "storeSize": "small", "storeVisitDate": "8/8/14", "action": "Purchase", "dollarAmount": "34" }, { "storeID": "24335234", "storeName": "Mike's Bikes", "city": "Townsville", "building": "2626", "street": "Aardvark Circle", "zipcode": "88888", "storeSize": "small", "storeVisitDate": "8/8/14", "action": "Purchase", "dollarAmount": "12.32" }] }, { "key": "10/3/15", "values": [{ "storeID": "24335234", "storeName": "Mike's Bikes", "city": "Townsville", "building": "2626", "street": "Aardvark Circle", "zipcode": "88888", "storeSize": "small", "storeVisitDate": "10/3/15", "action": "Purchase", "dollarAmount": "233.1" }, { "storeID": "24335234", "storeName": "Mike's Bikes", "city": "Townsville", "building": "2626", "street": "Aardvark Circle", "zipcode": "88888", "storeSize": "small", "storeVisitDate": "10/3/15", "action": "Return", "dollarAmount": "44.99" }] }] }]; fixData(stores); 

If we assume your array is called arr, I propose: 如果我们假设您的数组称为arr,我建议:

arr.forEach(function(currentValue, index, array) {
   currentValue.visits = currentValue.visits.map(function(currentValue, index, array) {
      currentValue.visitDate = currentValue.key;
      delete currentValue.key;
      currentValue.transactions = currentValue.values.map(function(currentValue, index, array) {
         currentValue = {action: currentValue.action, dollars: currentValue.dollarAmount};
         return currentValue;
      });
      delete currentValue.values;
      return currentValue;
   });
});

Well, since this is 'data' rather than some in-memory objects, I'm guessing you got it from JSON by using JSON.parse . 好吧,由于这是“数据”,而不是某些内存中的对象,所以我猜您是通过使用JSON.parse从JSON获得的。 (If not, you can still use this approach by first using JSON.strigify ) (如果没有,您仍然可以通过首先使用JSON.strigify来使用此方法)

Did you know JSON.parse accepts an function to control such things? 您知道JSON.parse接受用于控制此类事件的函数吗? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

So.... 所以....

fixed=JSON.parse(dataString, function(key,value){
 if(key=="key"){this.visitDate=value;return}
 if(key=="values"){this.transactions=value;return}
 if(key=="somethingYouDontWant"){return;}
 //etc...
 return value;    
})

Its pure javascript without any library and uses simple map: 它纯净的javascript,没有任何库,并使用简单的地图:

 var y = x.map(function(xs){
      xs.visits = xs.visits.map(function (item){
        return {
          visitDate: item.key,
          transactions: item.values.map(function(v){
            return {
              action: v.action,
              dollars: v.dollarAmount
            };
          })
        };
      });
      return xs;
    });

Flexible solution with Array.map() and delete operator: Array.map()delete运算符的灵活解决方案:

var delete_props = ["storeID","storeName","city","building","street", "zipcode","storeSize", "storeVisitDate"];

 // arr is your initial array
 arr.map(function(obj){
     obj['visits'].map(function(inner_obj){
         inner_obj['visitDate'] = inner_obj['key'];
         delete inner_obj['key'];

         inner_obj['values'].map(function(values_obj){
            values_obj['dollars'] = values_obj['dollarAmount'];
            delete values_obj['dollarAmount'];

            delete_props.forEach(function(v){
                delete values_obj[v];
            });
        });
        inner_obj['transactions '] = inner_obj['values'];
        delete inner_obj['values'];

     });     
 });

here is another solution, the code is pretty straightforward but not optimized. 这是另一种解决方案,代码非常简单,但尚未优化。

var obj = {}, key;
data.forEach(item => {
  item.visits.forEach(visit => {
    visit.visitDate = visit.key; 
    delete visit.key;
    visit.transactions = [];
    visit.values.forEach(value => {
      obj = {};
      for (key in value) {
        if (value.hasOwnProperty(key) && retain.indexOf(key) > -1) {
          obj[key] = value[key];
        }
      }
      visit.transactions.push(obj);
    });
    delete visit.values;
  });
console.log(item);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM