简体   繁体   English

获取嵌套对象和数组的值-使用plunker

[英]Getting values of nested objects and arrays - with plunker

I have two arrays, with nested objects, downloaded as part of calls to API endpoints, one (preview) has just numbers. 我有两个带有嵌套对象的数组,这些数组是作为对API端点的调用的一部分下载的,其中一个(预览)只有数字。

Example: 例:

[{
  obj1:[1, 2],
  obj2:[3, 4]
}]

I had to make a second call to another endpoint, to get a list of IDs with strings 我不得不再次调用另一个端点,以获取带有字符串的ID列表

Example: 例:

[{
  obj1:[{
    id:1,
    name:'string_name1'
  }, {
    id:2, 
    name:'string_name2'
  }]
}, {
  obj2:[{
    id:3, 
    name:'string_name3'
  }, {
    id:4, 
    name:'string_name4'
  }]
}];

I need to match the IDs to the first array of objects numbers, so I have strings/text values to display on my web page 我需要将ID与对象编号的第一个数组匹配,所以我要在网页上显示字符串/文本值

I have 2 functions 我有2个功能

The first one, pulls the numbers from the preview array and pushes them to my own editable array that I will use to display on the page 第一个,从预览数组中提取数字并将其推入我将用于显示在页面上的我自己的可编辑数组中

This is the array before function runs 这是函数运行之前的数组

 objName = [['obj1'], ['obj2']];

This is the first function, matches the names in preview to the names in my array and pushes values 这是第一个函数,将预览中的名称与数组中的名称匹配并推送值

    setNumbers(){
     for(let i = 0; i < this.objName.length; i++){
           for(var name in this.preview[0]) {
             if (name == this.objName[i][0]){
                  for(var val in  this.preview[0][name]) {
                       this.objName[i].push(this.preview[0][name][val])
                  }
             }

          }
     }
  this.setStrings()
}

The second matches the IDs in fields to the numbers in objName and replaces with the string value 第二个将字段中的ID与objName中的数字匹配,并替换为字符串值

public setStrings(){
  let feildId, feildName;
    for(let i = 0; i < this.fields.length; i++){
      var obj = this.fields[i]
        for(var name in obj) {
          if(this.objName[i][0] == name){
              for(let j = 0; j < obj[name].length; j++){
                feildId = obj[name][j].id
                feildName = obj[name][j].name;
                  for(let x = 0; x < this.objName[i].length; x++){
                    if (this.objName[i][x] == feildId){
                       var index = this.objName[i].indexOf(feildId)
                         if (index !== -1) {
                              this.objName[i][index] = feildName;
                          }

                    }
                  }
              }
          }
        }
    }

console.log(this.objName)
  }

The objName array, for output, ends up looking like: 输出的objName数组最终看起来像:

[['obj1', 'string_name1', 'string_name2'], ['obj2', 'string_name3', 'string_name4']]

It works, but makes my eyes hurt, there must be an easier cleaner way of doing this? 它起作用了,但是却让我的眼睛受伤了,必须有一种更简单,更清洁的方式来做到这一点?

Plunker link: https://plnkr.co/edit/KBDu3ZehHl04er6eut6r?p=preview 柱塞链接: https ://plnkr.co/edit/KBDu3ZehHl04er6eut6r ? p = preview

Your data structures are not ideal for this kind of transformation. 您的数据结构对于这种转换而言并不理想。 For instance, it would have been better if the display strings could be addressed directly given an "obj"-property and array index, without having to iterate through arrays. 例如,如果可以在给定“ obj”属性和数组索引的情况下直接寻址显示字符串,而不必遍历数组,那会更好。

Anyway, using the existing structure, you can still improve by using array functions, such as find and map : 无论如何,使用现有结构,您仍然可以使用数组函数(例如findmap

 class App { constructor(preview, objName, fields) { this.preview = preview; this.objName = objName; this.fields = fields; this.setNumbers(); } setNumbers() { this.objName = this.objName.map( arr => arr.concat(this.preview[0][arr[0]]) ); this.setStrings(); } setStrings() { this.objName = this.objName.map( arr => [arr[0]].concat(arr.slice(1).map( val => this.fields.find( field => arr[0] in field )[arr[0]] .find( item => item.id === val ).name )) ); console.log(this.objName); } } var objName = [['obj1'], ['obj2']], preview = [{ obj1: [1, 2], obj2: [3, 4] }], fields = [{ obj1:[{ id:1, name:'string_name1' }, { id:2, name:'string_name2' }] }, { obj2:[{ id:3, name:'string_name3' }, { id:4, name:'string_name4' }] }]; new App(preview, objName, fields); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Note that this code assumes all searches lead to matches. 请注意,此代码假定所有搜索均导致匹配。 If this is not your case, you'll have to add some code to define which values should be returned in case of non-matching references. 如果不是这种情况,则必须添加一些代码来定义在引用不匹配的情况下应返回哪些值。

Here is such a variant of the code: 这是代码的这种变体:

 class App { constructor(preview, objName, fields) { this.preview = preview; this.objName = objName; this.fields = fields; this.setNumbers(); } setNumbers() { this.objName = this.objName.map( arr => arr[0] in this.preview[0] ? arr.concat(this.preview[0][arr[0]]) : arr ); this.setStrings(); } setStrings() { this.objName = this.objName.map( arr => [arr[0]].concat(arr.slice(1).map( val => { let find = this.fields.find( field => arr[0] in field ); if (find) find = find[arr[0]].find( item => item.id === val ); return find ? find.name : val; })) ); console.log(this.objName); } } var objName = [['obj1'], ['obj2'], ['obj3']], preview = [{ obj1: [1, 2], obj2: [3, 4, 5], }], fields = [{ obj1:[{ id:1, name:'string_name1' }, { id:2, name:'string_name2' }] }, { obj2:[{ id:3, name:'string_name3' }, { id:4, name:'string_name4' }] }]; new App(preview, objName, fields); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

It's easier and cleaner to do this if you break it down into smaller pieces: 如果将其分解成小块,则更容易,更清洁:

 let objsToMap = [{ obj1: [1, 2, 7], obj2: [3, 4], obj3: [1, 2] }] let objValues = [{ obj1: [{ id: 1, name: 'string_name1' }, { id: 2, name: 'string_name2' }] }, { obj2: [{ id: 3, name: 'string_name3' }, { id: 4, name: 'string_name4' }] }]; function findValueForId(objDef, id) { let idKeyMap = objDef.find(item => item.id === id); return idKeyMap ? idKeyMap.name : null; } function findObjectValues(valueMapping, key) { let objectWithObjectValues = valueMapping.find(item => key in item); return objectWithObjectValues ? objectWithObjectValues[key] : null; } // returns an array containing key followed by the values corresponding to the specified ids function lookupObject(key, ids, valueMapping) { let objDef = findObjectValues(valueMapping, key) || []; let valuesForIds = ids.map(id => findValueForId(objDef, id)); let valuesWithoutBlanks = valuesForIds.filter(value => value); return [key].concat(valuesWithoutBlanks); } let result = Object.entries(objsToMap[0]).map(([k, v]) => lookupObject(k, v, objValues)); console.log(result); 

You'll notice that this approach uses .find() in two places because your second data structure nests everything into arrays instead of having direct property references. 您会注意到,该方法在两个地方都使用.find() ,因为第二个数据结构将所有内容嵌套在数组中,而不是具有直接的属性引用。 This isn't very good because it's not good for performance and makes the code more convoluted than it has to be. 这不是很好,因为它对性能不利,并且使代码比必须的更加复杂。

Another option is to rearrange the second array before consuming it, so that it's like this: 另一个选择是在使用第二个数组之前重新排列它,如下所示:

let objValues = {
  obj1: { 
    '1': 'string_name1',
    '2': 'string_name2'
  },
  obj2: {
    '3': 'string_name3', 
    '4': 'string_name4'
  }
};

Here's how you could do that: 这是您可以执行的操作:

 let objsToMap = [{ obj1: [1, 2, 7], obj2: [3, 4], obj3: [1, 2] }] let objValuesRaw = [{ obj1: [{ id: 1, name: 'string_name1' }, { id: 2, name: 'string_name2' }] }, { obj2: [{ id: 3, name: 'string_name3' }, { id: 4, name: 'string_name4' }] }]; function cleanupObjDef(objDef) { return objDef.reduce(function(acc, el) { acc[el.id] = el.name; return acc; }, {}); } function cleanupObjValues(objValues) { let allCombined = Object.assign({}, ...objValues); return Object.entries(allCombined).reduce(function (acc, [k, v]) { acc[k] = cleanupObjDef(v); return acc; }, {}); } // returns an array containing key followed by the values corresponding to the specified ids function lookupObject(key, ids, valueMapping) { let objDef = valueMapping[key] || {}; let valuesForIds = ids.map(id => objDef[id]); let valuesWithoutBlanks = valuesForIds.filter(value => value); return [key].concat(valuesWithoutBlanks); } let objValues = cleanupObjValues(objValuesRaw); let result = Object.keys(objsToMap[0]).map(key => lookupObject(key, objsToMap[0][key], objValues)); console.log(result); 

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

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