ardev
ardev

Reputation: 663

How to create a new array with a nested array as specific key value in JavaScript

If have an array like this:

let array = [ 
             {hash: "11223344", value: "abc"},
             {hash: "11223344", value: "def"},
             {hash: "22113344", value: "jkl"},
             {hash: "22113344", value: "zyw"},
             {hash: "33221144", value: "omn"},
             {hash: "33221144", value: "xyz"}
];

and I wanted to loop through that array and create a new array whereby each each hash is only listed once and each value that was listed with a given is added to an array at the key value in the object of the single hash, like this:

let newarray = [ 
             {hash: "11223344", value: ["abc", "def"]},
             {hash: "22113344", value: ["jkl", "zyw"]},
             {hash: "33221144", value: ["omn", "xyz"]},
]; 

How would I get there?

Im thinking its something like

array.map((item, i, self) => {
    let newArray =[];
    if(item.hash === newArray.hash){
        newArray.value.concat(item.value)
    } else {
        newArray.concat({hash: item.hash, value: [item.value]})
}

but how do I instantiate that array at first in the value key? Is my thinking right on the use of the Array.prototype.map()?

EDIT: I was asked to explain how this question is different than: How to group an array of objects by key

In contrast to the link, there is no need to group the results and I dont want to use a library like LoDash. The clarity provided about creating the array in the value key also has some worth.

I think the answers here also point out the need to use the index and provides several valid tools, some of which arent provided in the answers in the other questions. Tools such as reduce() and Set

Upvotes: 0

Views: 201

Answers (6)

Get Off My Lawn
Get Off My Lawn

Reputation: 36299

Use a set to get an unique list of hashes, then match each item on the unique set using filter and map.

let array = [ 
  {hash: "11223344", value: "abc"},
  {hash: "11223344", value: "def"},
  {hash: "22113344", value: "jkl"},
  {hash: "22113344", value: "zyw"},
  {hash: "33221144", value: "omn"},
  {hash: "33221144", value: "xyz"}
];

let a = [...new Set(array.map(i => i.hash))]
  .map(hash => {
    return { hash, values: array.filter(v => v.hash == hash).map(v => v.value) }
  })

console.log(a)

Upvotes: 2

You could simply use a for loop to achieve this:

array = [ 
     {hash: "11223344", value: "abc"},
     {hash: "11223344", value: "def"},
     {hash: "22113344", value: "jkl"},
     {hash: "22113344", value: "zyw"},
     {hash: "33221144", value: "omn"},
     {hash: "33221144", value: "xyz"}
];

newArray = []
for (var i = array.length - 1; i >= 0; i--) {

    if (newArray[array[i].hash] == null) {
        newArray[array[i].hash] = [array[i].value];
    } else {
        newArray[array[i].hash].push(array[i].value)
    }
}
console.log(newArray);

Upvotes: 0

Shubham Gupta
Shubham Gupta

Reputation: 2646

Take a look at the following code where we maintain the index of hash encountered before and insert the value to existing object else insert a new object in the results array.

let data = [{
    hash: "11223344",
    value: "abc"
  },
  {
    hash: "11223344",
    value: "def"
  },
  {
    hash: "22113344",
    value: "jkl"
  },
  {
    hash: "22113344",
    value: "zyw"
  },
  {
    hash: "33221144",
    value: "omn"
  },
  {
    hash: "33221144",
    value: "xyz"
  }
];


function aggregateValues(arr) {
  let hashMap = {};
  let result = [];
  arr.forEach((o) => {
    if (hashMap[o.hash] !== undefined) {
      result[hashMap[o.hash]].value.push(o.value);
    } else {
      hashMap[o.hash] = result.length;
      result.push({
        hash: o.hash,
        value: [o.value]
      });
    }
  })
  return result;
}

console.log(aggregateValues(data))

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386560

You could take a Map and render the collected items with Array.from.

var array = [{ hash: "11223344", value: "abc" }, { hash: "11223344", value: "def" }, { hash: "22113344", value: "jkl" }, { hash: "22113344", value: "zyw" }, { hash: "33221144", value: "omn" }, { hash: "33221144", value: "xyz" }],
    grouped = Array.from(
        array.reduce((map, { hash, value }) =>
            map.set(hash, (map.get(hash) || []).concat(value)), new Map),
        ([hash, value]) => ({ hash, value })
    );
    
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Sivakumar Tadisetti
Sivakumar Tadisetti

Reputation: 5031

You can use reduce like below

let array = [ 
   {hash: "11223344", value: "abc"},
   {hash: "11223344", value: "def"},
   {hash: "22113344", value: "jkl"},
   {hash: "22113344", value: "zyw"},
   {hash: "33221144", value: "omn"},
   {hash: "33221144", value: "xyz"}
];

let result = array.reduce((acc, ele) => {
   let index = acc.findIndex(e => e.hash === ele.hash);
   if (index == -1) {
    acc.push({
      hash: ele.hash,
      value: [ele.value]
    })
   } else {
    acc[index].value.push(ele.value);
   }
   return acc;
}, []);

console.log(result);

Upvotes: 0

brk
brk

Reputation: 50291

You can use reduce function to return a new array.Inside reduce callback use findIndex to find the index of the object where the hash matches. If this hash match then update the value array, else create a new object, set it's key and value and push it

let array = [{
    hash: "11223344",
    value: "abc"
  },
  {
    hash: "11223344",
    value: "def"
  },
  {
    hash: "22113344",
    value: "jkl"
  },
  {
    hash: "22113344",
    value: "zyw"
  },
  {
    hash: "33221144",
    value: "omn"
  },
  {
    hash: "33221144",
    value: "xyz"
  }
];

let reducedArray = array.reduce(function(acc, curr) {
  let getHashIndex = acc.findIndex(function(item) {
    return item.hash === curr.hash;
  })
  if (getHashIndex === -1) {
    let obj = {};
    obj.hash = curr.hash;
    obj.value = [];
    obj.value.push(curr.value);
    acc.push(obj)
  } else {
    acc[getHashIndex].value.push(curr.value)

  }
  return acc;
}, [])

console.log(reducedArray)

Upvotes: 1

Related Questions