简体   繁体   English

如何遍历嵌套对象并将值放入数组?

[英]How to iterate through a nested object and putting values into an array?

I created a nested object that holds the following format:我创建了一个包含以下格式的嵌套对象:

var lineMap = {
  2016: {
    Hemoglobin: 33 ,
    Lysozyme: 33 ,
    Myoglobin: 47 ,
    DNA: 13 ,
    Cytochrome C: 33
  },
  2017: {
    Hemoglobin: 8 ,
    Lysozyme: 47 ,
    Myoglobin: 8 ,
    DNA: 12 ,
    Cytochrome C: 33
  },
  2018: {
    Hemoglobin: 8 ,
    Lysozyme: 33 ,
    Myoglobin: 47 ,
    DNA: 12 ,
    Cytochrome C: 13
  },
  2019: {
    Hemoglobin: 8 ,
    Lysozyme: 8 ,
    Myoglobin: 47 ,
    DNA: 8 ,
    Cytochrome C: 47
  }
}

And I'd like to place each year's item count into its own index of an array such that:而且我想将每年的项目计数放入其自己的数组索引中,以便:

var arr = [
  [33, 33, 47, 13, 33],
  [8, 47, 8, 12, 33],
  [8, 33, 47, 12, 13],
  [8, 8, 47, 8, 47]
]

I have tried with creating a nested for loop to iterate through the nested object lineMap .我尝试创建一个嵌套的 for 循环来遍历嵌套对象lineMap

for (var i = 0; i < year.length; i ++){
  for (var j = 0; j < itemName.length; j++){
    temp_arr[j] = lineMap[year[i]][itemName[j]];
  }
  console.log("Index: " + i  + "\n" + temp_arr);
  arr[i] = temp_arr;
}
console.log(arr);

At the 5th line ( console.log(temp_arr) ), the console printed out what I expected--an array of the item count of its respective iteration:在第 5 行( console.log(temp_arr) ),控制台打印出我所期望的——其各自迭代的项目计数数组:

'Index: 0
33,33,47,13,33'
'Index: 1
8,47,8,12,33'
'Index: 2
8,33,47,12,13'
'Index: 3
8,8,47,8,47'

However, at the 8th line ( console.log(arr) ), I am not receiving my expected output.但是,在第 8 行( console.log(arr) ),我没有收到预期的输出。 Instead, I am getting:相反,我得到:

var arr = [
  [8, 8, 47, 8, 47],
  [8, 8, 47, 8, 47],
  [8, 8, 47, 8, 47],
  [8, 8, 47, 8, 47]
]

First, a warning: The order of the properties in those objects is defined, now, as of ES2015, but relying on that order is generally a bad idea.首先,警告:从 ES2015 开始,这些对象中属性的顺序现在定义,但依赖该顺序通常是一个坏主意。 Also, you seem to be using only ES5 level features, which don't define the order.此外,您似乎只使用 ES5 级别的功能,这些功能没有定义顺序。

So the best way, without relying on order, is to give yourself an array of the property names in the order you want them in your result arrays:因此,最好的方法,不依赖于顺序,是按照你希望它们在结果数组中的顺序给自己一个属性名称数组:

var keys = [
    "Hemoglobin",
    "Lysozyme",
    "Myoglobin",
    "DNA",
    "Cytochrome C"
];

Then something like this (see comments):然后是这样的(见评论):

// Loop through the years sorted lexicographically, building the result array
var arr = Object.keys(lineMap).sort().map(function(mainKey) {
    // Loop through the property names in the defined order, building
    // each inner array
    var entry = lineMap[mainKey];
    return keys.map(function(key) {
        return entry[key];
    });
});

Live Example:现场示例:

 var keys = [ "Hemoglobin", "Lysozyme", "Myoglobin", "DNA", "Cytochrome C" ]; var lineMap = { 2016: { Hemoglobin: 33 , Lysozyme: 33 , Myoglobin: 47 , DNA: 13 , "Cytochrome C": 33 }, 2017: { Hemoglobin: 8 , Lysozyme: 47 , Myoglobin: 8 , DNA: 12 , "Cytochrome C": 33 }, 2018: { Hemoglobin: 8 , Lysozyme: 33 , Myoglobin: 47 , DNA: 12 , "Cytochrome C": 13 }, 2019: { Hemoglobin: 8 , Lysozyme: 8 , Myoglobin: 47 , DNA: 8 , "Cytochrome C": 47 } }; // Loop through the years sorted lexicographically, building the // result array var arr = Object.keys(lineMap).sort().map(function(mainKey) { // Loop through the property names in the defined order, building // each inner array var entry = lineMap[mainKey]; return keys.map(function(key) { return entry[key]; }); }); console.log(arr);

If you want the years in numeric order, just add a callback to the sort :如果你想要数字顺序的年份,只需添加一个回调到sort

.sort(function(a, b) { return a - b; })

Tackling it in an ES2015+ world, I'd still keep the separate list of keys in the order you want them, so not a lot changes, it just gets a bit more concise:在 ES2015+ 世界中解决这个问题,我仍然会按照你想要的顺序保留单独的键列表,所以没有太多变化,它只是变得更简洁:

const arr = Object.entries(lineMap)
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([_, entry]) => keys.map(key => entry[key]));

Live Example:现场示例:

 const keys = [ "Hemoglobin", "Lysozyme", "Myoglobin", "DNA", "Cytochrome C" ]; const lineMap = { 2016: { Hemoglobin: 33 , Lysozyme: 33 , Myoglobin: 47 , DNA: 13 , "Cytochrome C": 33 }, 2017: { Hemoglobin: 8 , Lysozyme: 47 , Myoglobin: 8 , DNA: 12 , "Cytochrome C": 33 }, 2018: { Hemoglobin: 8 , Lysozyme: 33 , Myoglobin: 47 , DNA: 12 , "Cytochrome C": 13 }, 2019: { Hemoglobin: 8 , Lysozyme: 8 , Myoglobin: 47 , DNA: 8 , "Cytochrome C": 47 } }; const arr = Object.entries(lineMap) .sort(([a], [b]) => a.localeCompare(b)) .map(([_, entry]) => keys.map(key => entry[key])); console.log(arr);

That takes advantage of Object.entries , arrow functions , and destructuring assignment .这利用了Object.entries箭头函数解构赋值

And again, if you want those years in numeric order:再说一次,如果你想按数字顺序排列这些年份:

const arr = Object.entries(lineMap)
    .sort(([a], [b]) => a - b)
    .map(([_, entry]) => keys.map(key => entry[key]));

Your issue looks like the problem is with arr[i] = temp_arr;你的问题看起来像问题出在arr[i] = temp_arr; and sharing the same array reference.并共享相同的数组引用。 You need to start with a new array on each iteration.您需要在每次迭代时从一个新数组开始。 Or you need to clone it when copying it.或者你需要在复制它时克隆它。 arr[i] = temp_arr.slice(0)

Object.entries and map() will make your job easier. Object.entries 和 map() 将使您的工作更轻松。

 var lineMap = { 2016: { Hemoglobin: 33, Lysozyme: 33, Myoglobin: 47, DNA: 13, 'Cytochrome C': 33 }, 2017: { Hemoglobin: 8, Lysozyme: 47, Myoglobin: 8, DNA: 12, 'Cytochrome C': 33 }, 2018: { Hemoglobin: 8, Lysozyme: 33, Myoglobin: 47, DNA: 12, 'Cytochrome C': 13 }, 2019: { Hemoglobin: 8, Lysozyme: 8, Myoglobin: 47, DNA: 8, 'Cytochrome C': 47 } } console.log(Object.values(lineMap).map(o=>Object.values(o)))

First of all, you are using the exact same array every time, so when you do arr[i] = temp_arr you are assigning the same copy to each position of arr .首先,使用的是完全一样的阵列每一次,所以当你arr[i] = temp_arr要分配相同副本的每个位置arr You should create a new array each time.您应该每次都创建一个新数组。 Secondly, you cannot know the order of an object's keys, there is no guarantee that the keys will be ordered when iterating over them.其次,您无法知道对象键的顺序,不能保证在迭代键时键会被排序。 With this said, you could still use a fixed list of keys or sort them first.话虽如此,您仍然可以使用固定的键列表或先对它们进行排序。

let orderedKeys = ['Hemoglobin', 'Lysozyme', 'Myoglobin', 'DNA', 'Cytochrome C'];
let arr = Object.values(lineMap).map(el => orderedKeys.map(k => el[k]))

Result:结果:

> arr
0: [33, 33, 47, 13, 33]
1: [8, 47, 8, 12, 33]
2: [8, 33, 47, 12, 13]
3: [8, 8, 47, 8, 47]

If you're ok with ES6 syntax this will do the trick:如果您对 ES6 语法没问题,这将解决问题:

let result = [];
Object.values(lineMap).map(obj =>result.push(Object.values(obj)))

This will get you an array of arrays like you wanted.这将为您提供您想要的数组数组。 If you prefer a single array with all the results you can spread the second Object.values(obj) like so:如果您更喜欢包含所有结果的单个数组,您可以像这样传播第二个Object.values(obj)

Object.values(lineMap).map(obj =>result.push(...Object.values(obj)))

I created a function called yearsItemCount();我创建了一个名为yearsItemCount()的函数 Just call this and it will return what you want... Although it's O(N^2)只需调用它,它就会返回你想要的......虽然它是 O(N^2)

yearsItemCount = () => {

    let finalArr = []

      for(var line in lineMap) {
          let arr = [];
        for(var i in lineMap[line]) {
          arr.push(lineMap[line][i])
        }
        finalArr.push(arr);
      }
      return finalArr;
    }

or或者

Object.values(lineMap).map((a, b) => {
  return Object.values(a);
})

I don't know what's faster.我不知道什么更快。

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

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