最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to transform an array in to another array - Stack Overflow

programmeradmin2浏览0评论

I nave an array:

const arr = [
  { name: "aa", type: "total", count: 28394 },
  { name: "aa", type: "featured", count: 4 },
  { name: "aa", type: "noAnswers", count: 5816 },
  { name: "ba", type: "total", count: 148902 },
  { name: "ba", type: "featured", count: 13 },
  { name: "ba", type: "noAnswers", count: 32527 },
  { name: "cc", type: "total", count: 120531 },
  { name: "cc", type: "featured", count: 6 },
  { name: "cc", type: "noAnswers", count: 24170 }
];


const arrResult = [
  { name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
  { name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
  { name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];

I e up with this code:

let output = [];

const unique = [...new Set(arr.map(item => item.name))];

for(const key of unique) {
  let result = arr.filter(x => {
    return x.name === key;
  });
  output.push({
    name: key,
    // need to get the rest of the properties here
    // total
    // featured
    // noAnswers
  });
}

The only one thing I can not figure out is how to get the property names. Any ideas?

I nave an array:

const arr = [
  { name: "aa", type: "total", count: 28394 },
  { name: "aa", type: "featured", count: 4 },
  { name: "aa", type: "noAnswers", count: 5816 },
  { name: "ba", type: "total", count: 148902 },
  { name: "ba", type: "featured", count: 13 },
  { name: "ba", type: "noAnswers", count: 32527 },
  { name: "cc", type: "total", count: 120531 },
  { name: "cc", type: "featured", count: 6 },
  { name: "cc", type: "noAnswers", count: 24170 }
];


const arrResult = [
  { name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
  { name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
  { name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];

I e up with this code:

let output = [];

const unique = [...new Set(arr.map(item => item.name))];

for(const key of unique) {
  let result = arr.filter(x => {
    return x.name === key;
  });
  output.push({
    name: key,
    // need to get the rest of the properties here
    // total
    // featured
    // noAnswers
  });
}

The only one thing I can not figure out is how to get the property names. Any ideas?

Share Improve this question asked Jan 17, 2019 at 6:27 SerginoSergino 10.9k37 gold badges107 silver badges181 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 5

You can try something like this:

Idea:

  • Create a hashMap so you can group objects via name.
  • Then, add necessary properties to this group.
  • Finally, loop over keys and create final object with name property added back.

const arr = [ { name: "aa", type: "total", count: 28394 }, { name: "aa", type: "featured", count: 4 }, { name: "aa", type: "noAnswers", count: 5816 }, { name: "ba", type: "total", count: 148902 }, { name: "ba", type: "featured", count: 13 }, { name: "ba", type: "noAnswers", count: 32527 }, { name: "cc", type: "total", count: 120531 }, { name: "cc", type: "featured", count: 6 }, { name: "cc", type: "noAnswers", count: 24170 } ];

const hashMap = arr.reduce((acc, item) => {
  acc[item.name] = acc[item.name] || {};
  acc[item.name][item.type] = item.count;
  return acc;
}, {});

const result = Object.keys(hashMap).map((name) => Object.assign({}, {name}, hashMap[name] ));

console.log(result)


Working:

What I'm doing is I'm creating a new object for every new name. So, this: acc[item.name] = acc[item.name] || {}; checks if the entry is unavailable or not.

  • If unavailable, return a new object.
  • If available, return same object's reference.

So for any given name, you will only refer to same object.

Now this: acc[item.name][item.type] = item.count sets the properties. As we are referring to same object, you are setting property in one place. So if you have duplicate entries, say

[
    { name: "aa", type: "total", count: 28394 },
    { name: "aa", type: "total", count: 123},
]

output will have total: 123 instead.

So, at the end, you have a structure like:

{
  aa: {
    total: <something>,
    feature: <something>,
    ...
  }
}

Now all you have to do is merge the name in this object and return the value. You can also create the object with name property as default (as done by adiga). Thats something I didn't think while answering. So crediting instead of answering.

You can use reduce and destructuring like this:

The idea is to create an object with key as the name property and value as the final objects you need in the output. So, that you can simply use Object.values to get the final array:

const arr=[{name:"aa",type:"total",count:28394},{name:"aa",type:"featured",count:4},{name:"aa",type:"noAnswers",count:5816},{name:"ba",type:"total",count:148902},{name:"ba",type:"featured",count:13},{name:"ba",type:"noAnswers",count:32527},{name:"cc",type:"total",count:120531},{name:"cc",type:"featured",count:6},{name:"cc",type:"noAnswers",count:24170}];

const merged = arr.reduce((acc,{name,type,count}) =>
  ((acc[name] = acc[name] || {name})[type] = count, acc)
,{})

console.log(Object.values(merged))

This is equivalent to :

const arr=[{name:"aa",type:"total",count:28394},{name:"aa",type:"featured",count:4},{name:"aa",type:"noAnswers",count:5816},{name:"ba",type:"total",count:148902},{name:"ba",type:"featured",count:13},{name:"ba",type:"noAnswers",count:32527},{name:"cc",type:"total",count:120531},{name:"cc",type:"featured",count:6},{name:"cc",type:"noAnswers",count:24170}];

/* Our goal is to create a merged object like this:
{
  "aa": {
    "name": "aa",
    "total": 28394,
    "featured": 4,
    "noAnswers": 5816
  },
  "ba": {
    "name": "ba",
    "total": 148902,
    ....
  },
  "cc": {
    "name": "cc",
     ......
  }
}

The advantage of using object accumulator is we can access it like this: acc[name]
*/

const merged = arr.reduce((acc, {name,type,count} /*Destructuring*/) => {
  /* if the accumulator doesn't have the current "name" key, 
   create new object
   else use the existing one;
   {name} is same as {name: name}
  */
  acc[name] = acc[name] || {name};
  
  /* To the inner object, 
      add a key with the "type" value and assign it to "count" value
  */
  acc[name][type] = count;
  
  // return the accumulator
  return acc;
}, {})

// use Object.values to get the value part of the merged obejct into an array
console.log(Object.values(merged))

var op = {name : key};

  for(i=0; i < result.length; i++){
    op[result[i].type] = result[i].count;
  }

  output.push(op);

just adding this will work fine. However your code is not the most efficient. Hashing based on name will make it faster

const arr = [
  { name: "aa", type: "total", count: 28394 },
  { name: "aa", type: "featured", count: 4 },
  { name: "aa", type: "noAnswers", count: 5816 },
  { name: "ba", type: "total", count: 148902 },
  { name: "ba", type: "featured", count: 13 },
  { name: "ba", type: "noAnswers", count: 32527 },
  { name: "cc", type: "total", count: 120531 },
  { name: "cc", type: "featured", count: 6 },
  { name: "cc", type: "noAnswers", count: 24170 }
];

let output = [];

const unique = [...new Set(arr.map(item => item.name))];

for(const key of unique) {
  let result = arr.filter(x => {
    return x.name === key;
  });
  
  var op = {name : key};
  
  for(i=0; i < result.length; i++){
    op[result[i].type] = result[i].count;
  }
  
  output.push(op);
}

console.log(output);

The following is the most efficient way of doing it :

const arr = [
      { name: "aa", type: "total", count: 28394 },
      { name: "aa", type: "featured", count: 4 },
      { name: "aa", type: "noAnswers", count: 5816 },
      { name: "ba", type: "total", count: 148902 },
      { name: "ba", type: "featured", count: 13 },
      { name: "ba", type: "noAnswers", count: 32527 },
      { name: "cc", type: "total", count: 120531 },
      { name: "cc", type: "featured", count: 6 },
      { name: "cc", type: "noAnswers", count: 24170 }
    ];
 
 var hash = {};
 var result = [];
 
 for(var i=0; i < arr.length; i++){
  if(!arr[i].name in hash)
    hash[arr[i].name] = {}
  let temp = {};
  temp[arr[i].type] = arr[i].count;
  hash[arr[i].name] = Object.assign(temp, hash[arr[i].name]);  
 }
 
 for(var key in hash)
  result.push({name : key, ...hash[key]})
  
console.log(result)
 

You can use find operator of javascript to grab the desired row from arrResult Change your code like below-

for(const key of unique) {
  let result = arr.filter(x => {
    return x.name === key;
  });
  var currResult = arrResult.find(x => x.name == key);
  output.push({
    name: key,
    // need to get the rest of the properties here
    total: currResult.total,
    featured: currResult.featured,
    noAnswers: currResult.noAnswers
  });
}

JSFiddle: https://jsfiddle/ashhaq12345/z8royg5w/

const arr = [
  { name: "aa", type: "total", count: 28394 },
  { name: "aa", type: "featured", count: 4 },
  { name: "aa", type: "noAnswers", count: 5816 },
  { name: "ba", type: "total", count: 148902 },
  { name: "ba", type: "featured", count: 13 },
  { name: "ba", type: "noAnswers", count: 32527 },
  { name: "cc", type: "total", count: 120531 },
  { name: "cc", type: "featured", count: 6 },
  { name: "cc", type: "noAnswers", count: 24170 }
];

const names = [...new Set(arr.map(item => item.name))]
const output = {};

names.forEach(name => {output[name] = {}});

arr.forEach(item => {
  output[item.name][item.type] = item.count
});

const result = Object.entries(output).map(([name, rest]) => ({name, ...rest}))
console.log(result);

const arrResult = [
  { name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
  { name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
  { name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];

You can simply use for loop to iterate over your array and take a temp array and take map and fill the map using required data and then push your map into temp array like following.

const arr = [
  { name: "aa", type: "total", count: 28394 },
  { name: "aa", type: "featured", count: 4 },
  { name: "aa", type: "noAnswers", count: 5816 },
  { name: "ba", type: "total", count: 148902 },
  { name: "ba", type: "featured", count: 13 },
  { name: "ba", type: "noAnswers", count: 32527 },
  { name: "cc", type: "total", count: 120531 },
  { name: "cc", type: "featured", count: 6 },
  { name: "cc", type: "noAnswers", count: 24170 }
];

let result = [];
for( var i = 0; i < arr.length; i++)
{
   let data = {};
   if( arr[i].type == 'total')
   {
      data.name = arr[i].name;
      data.total = arr[i].count;
      data.featured = arr[i+1].count;
      data.noAnswers = arr[i+2].count;
      result.push(data);
   }
}

console.log(result);

发布评论

评论列表(0)

  1. 暂无评论