2

I have a 2D array like below:

1230 | this is a test
1278 | my new test
1230 | test2
7654 | testing...

I want to transform the array so that values are unique in the first column and the second column stores the concatenated text associated with that particular value. See example below.

1230 | this is a test -- test2
1278 | my new test
7654 | testing...

I understand I should first sort the array by its first column and then do the merging.

Here is the code for sorting the array by the first column:

var x = exp_arr.sort(function(a,b){ return a[0] > b[0] ? 1 : -1; });
alert(x);

I am a bit lost about how to do the merging. Your suggestions are most welcome

1
  • Merge by copying the items to a new array if the "id" is not present and merging if it is. Sort the resulting array passing a custom comparator function. Commented Sep 30, 2014 at 15:41

3 Answers 3

4

You can use the reduce command like so:

var array = [[1230, "this is a test"], [1278, "my new test"], [1230, "test2"], [7654, "testing..."]];

var result =
    array.reduce(function(ob, ar) {
              if (!(ar[0] in ob.nums)) {
                  ob.nums[ar[0]] = ar
                  ob.result.push(ar);
              } else
                  ob.nums[ar[0]][1] = (ob.nums[ar[0]][1]) + " -- " + ar[1];

              return ob
          }, {nums:{}, result:[]}).result
    .sort(function(a,b) {
        return a[0] - b[0];
    });

Fiddle here.

Reduce documentation here.

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

1 Comment

Thank you so much. The link to the documentation was very helpful indeed :)
1

First group array elements with the same first value into object whose keys are the first element, and values are arrays of second elements:

groups = array.reduce(function(result, elt) {
    result[elt[0]] = (result[elt[0]] || []).concat(elt[1]);
    return result;
});

Then map the object back into an array, by joining the members of each key's array with --.

Object.keys(groups).map(function(key) { return [key, groups[key].join(' -- '); })

Or, taking a leaf out of @friedi's book, taking advantage of sorting the array first, but using reduce instead of filter, which is slightly simpler because it means we do not need a IIFE to close around a previous item:

array.sort(sortfunc).reduce(result, item) {
    var prev = result[result.length-1] || [];
    if (prev[0] === item[0]) {
        prev[1] += " -- " + item[1];
    } else {
        result.push(item);
    }
}, []);

Either is far more readable than the accepted solution.

Comments

1

You can do this:

var x = exp_arr.sort(function(a,b){ return a[0] > b[0] ? 1 : -1; }).filter((function() {
    var prev = [null];
    return function(item) {
        if(prev[0] === item[0]) {
            prev[1] += ' -- ' + item[1];
            return false;
        }
        prev = item;
        return true;
    };
}()));

Explanation:
The filter function takes advantage of the fact that the array is already sorted. So every element is compared with the previous element (herefore a closure was used to save the previous element). If the previous element has the same id, we append the string to the previous element.

Here is the jsfiddle-demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.