tenten
tenten

Reputation: 1276

creating custom array from existing array in javascript

I have an array like below:

var search = [
    { code: "t1", name1: "n1", name2: "n2" },
    { code: "t1", name1: "n5", name2: "n6" },
    { code: "t2", name1: "n10", name2: "n11" },
    { code: "t2", name1: "n18", name2: "n20" },
    { code: "t3", name1: "n18", name2: "n20" },
];

I want to transform this array to the format below:

var finald = [
    { code: "t1", name1: "n1,n5", name2: "n2,n6" },
    { code: "t2", name1: "n10,n18", name2: "11,n20" },
    { code: "t3", name1: "n18", name2: "n20" },
];

I have tried this as below code. but no success. First I gathered all unique codes from the array:

var flags = [];
var codes = [];
for(var z=0; z<search.length; z++){
    if( flags[data[z].code]) continue;
    flags[data[z].code] = true;
    codes.push(data[z].code);
}

var finald = [];
for(var i=0; i<search.length; i++){

    var name1 = [];
    var name2 = [];
    for(var y=0; y<codes.length; y++){
        if(codes[y] == search[i].code ){

                var row = {
                    code: codes[y],
                    name1:search[i].name1,
                    name2:search[i].name2,


                };
                finald.push(row);
        }
    }   
}

Please Help.

Upvotes: 1

Views: 441

Answers (9)

Hassan Imam
Hassan Imam

Reputation: 22534

You can use array#reduce to group your array based on code and push same values in an array. Get all the values using Object.values() and then using array#map convert the array into a string using array#join().

var search = [{ code: "t1", name1: "n1", name2: "n2" },{ code: "t1", name1: "n5", name2: "n6" },{ code: "t2", name1: "n10", name2: "n11" },{ code: "t2", name1: "n18", name2: "n20" },{ code: "t3", name1: "n18", name2: "n20" }],
    result = Object.values(search.reduce((r,{code,name1, name2}) => {
        r[code] = r[code] || {code, name1: [], name2: []};
        r[code].name1.push(name1);
        r[code].name2.push(name2);
        return r;
      },{}))
    .map(({code,name1,name2}) => ({code, name1: name1.join(','), name2: name2.join(',')}));
console.log(result);

Upvotes: 0

Ofir G
Ofir G

Reputation: 754

it's not exactly what you asked for, but still try this approach.

you basically want to do a 'join' action on the array by the key 'code', so maybe try to convert your array to a map object - key: code , value : {name1, name2}

jsfiddle

var search = [
  {code:"t1", name1:"n1", name2:"n2"},
  {code:"t1", name1:"n5", name2:"n6"},
  {code:"t2", name1:"n10", name2:"n11"},
  {code:"t2", name1:"n18", name2:"n20"},
  {code:"t3", name1:"n18", name2:"n20"}];

const myMap = new Map();

search.forEach((obj) => {
  const key = obj.code;
  if(!myMap.has(key)) {
    myMap.set(key, {
      'name1' : obj.name1,
      'name2' : obj.name2
    });
  } else {
    var ele = myMap.get(key);
    ele.name1 = `${ele.name1},${obj.name1}`;
    ele.name2 = `${ele.name2},${obj.name2}`;
  }
}); 
console.log(myMap);

/*
    key: "t1" => value: {name1:"n1,n5", name2:"n2,n6"},
    key: "t2" => value: {name1:"n10,n18", name2:"n11,n20"},
    key: "t3" => value: {name1:"n18", name2:"n20"}
*/

if you must have it in an array form add this to the above, jsfiddle

var resArray = [];
myMap.forEach((value, key) => {
    resArray.push(Object.assign({'code': key}, value));
});

console.log(resArray);

/*
    [{ code: "t1", name1: "n1,n5", name2: "n2,n6" },
     { code: "t2", name1: "n10,n18", name2: "11,n20" },
     { code: "t3", name1: "n18", name2: "n20" }]
*/

Upvotes: 1

JJWesterkamp
JJWesterkamp

Reputation: 7916

Another take to fix the problem - this code emphasizes on immutability of data, returning new objects from all iterations. This might prevent hard to find bugs when performing such operations:

var finald = transform([
    { code: "t1", name1: "n1", name2: "n2" },
    { code: "t1", name1: "n5", name2: "n6" },
    { code: "t2", name1: "n10", name2: "n11" },
    { code: "t2", name1: "n18", name2: "n20" },
    { code: "t3", name1: "n18", name2: "n20" },
]);

console.log(finald);

function transform(source) {

    const keyedByCode = source.reduce((acc, item) => {
        const { name1 = [], name2 = [] } = acc[item.code] || {};
        return Object.assign({}, acc, {
            [item.code]: {
                name1: [item.name1, ...name1],
                name2: [item.name2, ...name2],
            },
        });
    }, {});

    return Object.keys(keyedByCode).map((code) => ({
        code,
        name1: keyedByCode[code].name1.sort().join(','),
        name2: keyedByCode[code].name2.sort().join(','),
    }));
}
.as-console-wrapper { max-height: 100% !important; }

Upvotes: 0

Alex Green
Alex Green

Reputation: 537

The order of codes doesn't matter here:

const search = [{code:"t1", name1:"n1", name2:"n2"},
         {code:"t1", name1:"n5", name2:"n6"},
         {code:"t2", name1:"n10", name2:"n11"},
         {code:"t2", name1:"n18", name2:"n20"},
         {code:"t3", name1:"n18", name2:"n20"}];

function combineObjectsByCode(objects) {
  let codes = new Set();
  objects.forEach(object => codes.add(object.code));

  let combinedObjects = [];
  codes.forEach(code => {
    let objectsWithSameCode = objects.filter(object => object.code === code);

    let combinedObject;
    objectsWithSameCode.forEach( obj => {
      if (!combinedObject) {
        combinedObject = obj;
      }
      else {
        combinedObject.name1 = combinedObject.name1 + ', ' + obj.name1; 
        combinedObject.name2 = combinedObject.name2 + ', ' + obj.name2;     
      }      
    })
    combinedObjects.push(combinedObject);
  });
  
  return combinedObjects;
}

console.log(combineObjectsByCode(search));

Upvotes: 0

Eddie
Eddie

Reputation: 26844

You can use reduce and map

let search = [{code:"t1", name1:"n1", name2:"n2"},{code:"t1", name1:"n5", name2:"n6"},{code:"t2", name1:"n10", name2:"n11"},{code:"t2", name1:"n18", name2:"n20"},{code:"t3", name1:"n18", name2:"n20"},];

let result = Object.values( search.reduce( (c,v) => {
    c[ v.code ] ? c[ v.code ].push( v ) : c[ v.code ] =[ v ];
    return c;
},{}) ).map( v => {
    let n1 = [], n2 = [];
    v.forEach( e => { n1.push( e.name1 ); n2.push( e.name2 ); });
    return { code : v[0].code,  name1 : n1.join(","), name2 : n2.join(",") }
});

console.log( result );

Upvotes: 0

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

You can create your own custom logic for this:

var search = [
    { code: "t1", name1: "n1", name2: "n2" },
    { code: "t1", name1: "n5", name2: "n6" },
    { code: "t2", name1: "n10", name2: "n11" },
    { code: "t2", name1: "n18", name2: "n20" },
    { code: "t3", name1: "n18", name2: "n20" },
];
//this is the result array
var result = [];
//this is a flag
var itemExist = false;
search.forEach((item) => {
  //reset flag to false
  itemExist = false;
  //check if the object already exist in the result array or not
  for(var i=0; i<result.length; i++){
    //if the object exist then merge the values of name1 and name2
    if(result[i].code === item.code){
        result[i].name1 = result[i].name1 +','+item.name1;
        result[i].name2 = result[i].name2 +','+item.name2;
        itemExist = true;
        //break the for loop
        break;
    }
  }
  //if object do not exist in the result array then push it
  if(!itemExist){
    result.push(item);
  }
});

console.log(result);

Upvotes: 0

mplungjan
mplungjan

Reputation: 177975

Something like this?

You could use reduce or map but this is more understandable in my opinion for a simple task

I am assuming the search is ordered by code.

var search = [
         {code:"t1", name1:"n1", name2:"n2"},
         {code:"t1", name1:"n5", name2:"n6"},
         {code:"t2", name1:"n10", name2:"n11"},
         {code:"t2", name1:"n18", name2:"n20"},
         {code:"t3", name1:"n18", name2:"n20"}
    ],
    finald = [];

finald.push(search[0]);

for (var i = 1; i < search.length; i++) {
  var f = finald[finald.length - 1];
  if (f.code == search[i].code) {
    f.name1 += ","+search[i].name1;
    f.name2 += ","+search[i].name2;
  } else {
    finald.push(search[i]);
  }

}
console.log(finald);

Upvotes: 0

F.Almeida
F.Almeida

Reputation: 413

I wrote this function:

function normalize(arr) {
    var output = [];
      for(var i = 0; i < arr.length; i++) {
        var codeIndex = _findIndex(output, arr[i].code);
        if(codeIndex !== -1) {
          // Code already in output array, merge names.
          output[_findIndex(output, arr[i].code)].name1 += ', ' + arr[i].name1;
          output[_findIndex(arr[i].code)].name2 += ', ' + arr[i].name2;
        }
        else {
          // Code new to output array, pus into.
          output.push(arr[i]);
        }
      }

      return output;

      //
      // Privates
      //

      function _findIndex(arr, code){
        var index = -1;
        for(var i = 0; i < arr.length; i++){
          if(arr[i].code == code) {
            index = i;
            break;
          }
        }
        return index;
      }
    }

Output:

0 : {code: "t1", name1: "n1, n5", name2: "n2, n6, n20"}
1 : {code: "t2", name1: "n10, n18", name2: "n11"}
2 : {code: "t3", name1: "n18", name2: "n20"}

Upvotes: 0

Maxime Lequain
Maxime Lequain

Reputation: 96

This should do what you want:

var search = [
  { code: "t1", name1: "n1", name2: "n2" },
  { code: "t1", name1: "n5", name2: "n6" },
  { code: "t2", name1: "n10", name2: "n11" },
  { code: "t2", name1: "n18", name2: "n20" },
  { code: "t3", name1: "n18", name2: "n20" }
];
    

const items = search.reduce((acc, item) => {
  const code = item.code;
  if (!acc[code]) acc[code] = {name1: [], name2: []};
  acc[code].name1.push(item.name1);
  acc[code].name2.push(item.name2);
  return acc;
}, {});

const finald = Object.keys(items).reduce((acc, key) => {
  const item = items[key];
  acc.push({
    code: key,
    name1: item.name1.join(','),
    name2: item.name2.join(',')
  });
  return acc;
}, []);

Upvotes: 0

Related Questions