1

I want to modify a Javascript array, so that the elements having the same values for specifies properties merge into one object in a way that the other properties are kept as a comma-separated string, JSON string, or an array. Basically, I want to turn this:

[
    {
        "language" : "english",
        "type" : "a",
        "value" : "value1"
    },
    {
        "language" : "english",
        "type" : "a",
        "value" : "value2"
    },
    {
        "language" : "english",
        "type" : "b",
        "value" : "value3"
    },  
    {
        "language" : "spanish",
        "type" : "a",
        "value" : "valor1"
    }
]

into this:

[
    {
        "language" : "english",
        "type" : "a",
        "value" : ["value1" , "value2"]  // A Json string is welcome too
    },
    {
        "language" : "english",
        "type" : "b",
        "value" : "value3"
    },  
    {
        "language" : "spanish",
        "type" : "a",
        "value" : "valor1"
    }
]

I have tried iterating and filtering, then upserted the object as given in the snippet. But I wonder if there is a more elegant way to do that.

P.S EcmaScript6 and additional JS library suggestions are also welcome.

var originalArray = [
	{
		"language" : "english",
		"type" : "a",
		"value" : "value1"
	},
	{
		"language" : "english",
		"type" : "a",
		"value" : "value2"
	},
	{
		"language" : "english",
		"type" : "b",
		"value" : "value3"
	},	
	{
		"language" : "spanish",
		"type" : "a",
		"value" : "valor1"
	}
];

var resultingArray = [];

// iterate through the original array
$.each(originalArray, function(i, val) {
  // apply filter on key properties (i.e. language and type)
  var result = resultingArray.filter(function( obj ) {
    return (obj.language === val.language && obj.type === val.type);
  });
  // if a record exists, update its value
  if (result.length === 1) {  
    result[0].value += (", " + val.value);
  } 
  // else, add value
  else if (result.length === 0) {
    resultingArray.push(val);
  }
  // if multiple rows exist with same key property values...
  else {
    alert("Too many records with language '" + val.language + "' and type '" + val.type + "'");
  }
});

console.log(JSON.stringify(resultingArray));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

7
  • 1
    Here was my suggested solution, depending on what you consider "elegant". The trouble with your code is it runs in O(N^2), since the filter function runs once on the first iteration of each, twice, on the second iteration, and so on. There's no need for that. Commented Jul 27, 2016 at 9:57
  • 1
    And here was mine, where value is always an array. BTW: I think your alert() statement can never be triggered. If you don't want twice the same value for the same key (language + type), you'll have to do it differently. Commented Jul 27, 2016 at 10:04
  • hey, your JS was using jQuery, why you don't add jQuery tag? I was learn and make sure using pure javascript forEach to help you -_-! Commented Jul 27, 2016 at 10:12
  • 1
    Incidentally, I'm not sure it can be seen an exact duplicate of the suggested question as the OP is using a composite key, making the existing answers inadequate. Commented Jul 27, 2016 at 10:18
  • @Arnauld I'm not sure adding a secondary check warrants an entirely new question. The answers given are entirely appropriate, they just require a small modification. Commented Jul 27, 2016 at 11:07

1 Answer 1

1

This is what you need?

var baseData= [
    {
        "language"  : "english",
        "type" : "a",
        "value" : "value1"
    },
    {
        "language" : "english",
        "type" : "a",
        "value" : "value2"
    },
    {
        "language" : "english",
        "type" : "b",
        "value" : "value3"
    },  
    {
        "language" : "spanish",
        "type" : "a",
        "value" : "valor1"
    }
];

var newData = [];
baseData.forEach(function(item, index) {
  if (newData.length === 0) {
    newData.push(item);
    
  } else {
    var dIndex = -1;
    newData.forEach(function(itm, idx) {
      if (item.language === itm.language && item.type === itm.type) dIndex = idx;
    });
    
    if (dIndex !== -1) {
      var oldValue = newData[dIndex].value;
      
      if (typeof(oldValue).toString() === 'string') {
        newData[dIndex].value = [oldValue, item.value];
      }
    } else {
      newData.push(item);
    }
  }
});
console.log(newData);

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.