简体   繁体   中英

Javascript - functional approach to remove empty elements from end of array

The input array is the following:

var arr = ["some", "", "", "value", "", "", ""];

I need to remove the empty elements from the tail. So the expected output is:

["some", "", "", "value"]

I know a boring reverse loop would work, or pop() until it comes to the first non-empty element. Eg:

while(arr.pop() === "")

However, just for fun i would love to see an equally or more efficient (if possible) functional approach.

My first functional idea was implementing it with reverse -> reduce -> reverse . However it seems to complex, so i wanted to see if somebody has a better approach.

var arr = ["some", "", "", "value", "", "", ""];

var result = arr.reverse()
    .reduce(function (a, b) {
        if (b != "")
            a.addallnext = true;

        if (a.addallnext === true)
            a.result.push(b);

        return a;
    }, {
        addallnext: false, result: []
    }).result.reverse();

Here is my fiddle:

http://jsfiddle.net/fy4cuspq/1/

Preferably i would love the algorithm to use built-in array methods, but if you have some amazing custom method or similar to add to the prototype, that would be great.

Note : My goal is not to substitute a more efficient iterative approach with a less efficient functional approach etc... it's just an exploration of functional beauty ;)

You could use reduceRight . I'm using Array.prototype.concat to keep code free of mutations. Also, I rely on the length of the result to see when to stop removing empty strings.

var reducedArray = arr.reduceRight(function (result, a) {
  return result.length === 0 && a === ""
       ? result
       : [a].concat(result);
}, []);

How about simply removing the last element as long as it's an empty string ?

var arr = ["some", "", "", "value", "", "", ""];

while ( arr.getLast() == "" )  arr.pop();

(EDIT: OP just edited the question saying that he doesn't want this particular method.. )

I think I have a more efficient one that @Ionut although his looks prettier.

perf ( 22% ) | fiddle

arr.reverse();
arr.some(function(elem, i, array) {
  if (elem) {
    array.splice(0, i);
    return true;
  } else return false;
});
arr.reverse();

Hope it helps! :)

The problem boils down to finding the length of the initial subarray which does not end with the empty string. Since Javascript's Array.prototype.reduce is kind enough to provide the current index into the array, this can be achieved with a simple reduce :

function trim(arr) { 
  return arr.slice(0,arr.reduce(function(i,b,j){return b===""?i:j+1},0))
}

In the reduce , the first argument at each point is the length of the current trimmed segment. Since the third argument is the current index , it needs to be incremented to produce the current length .

If reduce didn't provide the extra arguments to the callback, you could do it (still functionally, but less legibly) by passing a pair of values through the reduction:

function trim(arr) { 
  return arr.slice(0,arr.reduce(
      function(ij,b){
          return [b===""?ij[0]:ij[1]+1,
                  [ij[1]+1]
      },[0,0])[0])
}

I know there will be some complications with stringfy and parse, but here's my one liner with Regex:

var arr = ["some", "", "", "value", "", "", ""];
var result = JSON.parse(JSON.stringify(arr).replace(/(,"")+]$/,"]"))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM