Reputation: 14274
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. E.g.:
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 ;)
Upvotes: 1
Views: 390
Reputation: 179139
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);
}, []);
Upvotes: 8
Reputation: 241821
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])
}
Upvotes: 1
Reputation: 4135
I think I have a more efficient one that @Ionut although his looks prettier.
arr.reverse();
arr.some(function(elem, i, array) {
if (elem) {
array.splice(0, i);
return true;
} else return false;
});
arr.reverse();
Hope it helps! :)
Upvotes: 1
Reputation: 3778
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(/(,"")+]$/,"]"))
Upvotes: 0
Reputation: 19788
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.. )
Upvotes: 1