Willem de Wit
Willem de Wit

Reputation: 8742

Combining some array items

I'm kind of new to functional programming and I try to do the following: Let's say I have an array of values: ['a','b-','c'] and I want that every item which ends with a '-' is merged with the following array entry: ['a','b-c'].

Of course I can do this by making a for-loop:

var test = ['a', 'b-', 'c'], result = [];

for (var i=0;i<test.length;i++) {
  var curr = test[i];
  if (curr.endsWith('-')) {
    curr += test[i+1];
    i++;
  }
  result.push(curr);
}

But how can one do this without the for loop?

Upvotes: 3

Views: 152

Answers (6)

Cerbrus
Cerbrus

Reputation: 72957

To be honest, the way you programmed is probably the most efficient way to do this.

However, here's another option:

var test = ['a', 'b-', 'c'],
    result = test.join().replace(/-,/g, '').split(',');

console.log(result);

This joins all elements into a string: 'a,b-,c', removes all occurrences of '-,' > 'a,bc', then splits the string back up into an array with the desired result, as you can see in the output.

This can be fool-proofed a bit, by changing the separator used in the join / split:

var test = ['a', 'b-', 'c'],
    separator = '||',
    result = test.join(separator)
        .replace(new RegExp('-' + separator, 'g'), '')
        .split(separator);

Upvotes: 5

Thomas
Thomas

Reputation: 3593

Didn't read all answers, so sry if I repeat sth. that has already been said.

Functional programming doesn't mean that there is always a predefined function that does exactly what you intend to; or a combination of some.
Sometimes it is better to write a simple short utility-function than abusing the ones that are already there.

How about some "problems" like multiple dashed-values next to each other, or at the end of the list? How do you want to handle these cases?
This would be my implementation:

function combineDashedStrings(arr){
    var result = [], pending = ""
    for (var i=0; i<arr.length; i++) {
        var curr = pending + arr[i];

        pending = curr.endsWith("-") && curr || "";                 //multiple concats
        //pending = !pending && curr.endsWith("-") && curr || "";   //single concat

        pending || result.push(curr);
    }
    //pending && result.push(curr); //add last item if it contains a dash
    return result
}

combineDashedStrings(['a', 'b-', 'c-', 'd', 'e-']);

feel free to switch the commented lines/options

Upvotes: 0

Hatchet
Hatchet

Reputation: 5428

This can also be achieved using Array.prototype.map:

var test = ['a', 'b-', 'c'];

var result = test.slice().map(function (x, i, a) {
    if (x.endsWith("-") && a[i+1]) {
        var r = x + a[i+1]; // Join this and the next element in the array
        a.splice(i, 1); // Remove the next element from the array
        return r;
    }
    return x;
}).filter(function (x) {
    return typeof x !== 'undefined';
}); // Since the array comes back with a different length and some undefined elements, remove those. Thanks @Cerbrus for pointing this out

console.log(test, result, result.length); // ["a", "b-", "c"] ["a", "b-c"] 2

Upvotes: 1

nylki
nylki

Reputation: 503

Another map + filter one. Most likely slower, as filter add's another iteration through the array, but works as the original does (which is probably not what the OP wants when there are multiple -'s in a row).

var test = ['a', 'b-', 'c-', 'd', 'e'], result = [];

result = test
	.map((curr, i, array) => (curr.endsWith('-') && array[i + 1] !== undefined) ? curr + array[i+1] : curr)
	.filter((curr, i, arr) => (i>0 && arr[i-1].length > 1 && curr.length === 1) ? false : true)

document.write(result);

Upvotes: 0

Sawyer Charles
Sawyer Charles

Reputation: 126

This way will work for multiple dashed elements in a row, and if the last element has a dash, uses Array.forEach

var test = ['a', 'b-', 'c-'], result = [], next = "";

test.forEach(function(curr) {
  if (curr.endsWith('-')) {
    next += curr;
    if (curr == test[test.length-1]) {
      result.push(next);
    }
 }else {
   result.push(next + curr);
   next = "";
 }
});
document.write(result);

Upvotes: 0

raina77ow
raina77ow

Reputation: 106483

One possible approach (with .reduce):

var arr = ['a', 'b-', 'c'];
var trans = arr.reduce(function(acc, cur) {
  if (acc.length && acc[acc.length - 1].slice(-1) === '-') {
    acc[acc.length - 1] += cur;
  }
  else {
    acc.push(cur);
  }
  return acc;
}, []);

Upvotes: 2

Related Questions