Reputation: 23100
Is there a way to filter an array and if it returns no objects default to the default option in a single chain?
e.g.
[1,2,3]
.filter(isDivisibleByTen)
// otherwise return whatever
I could write it like so
const result [1,2,3].filter(isDivisibleByTen)
result ? result [0]
Upvotes: 1
Views: 72
Reputation: 10801
Maybe reduce is the only Array method that provides the array and can return an arbitrary value so you can use it:
[1,2,3]
.filter(isDivisibleByTen)
.reduce((_1, _2, _3, array) => array, 'defaultValue');
This solution is a bit processor-time-wasting (loops over the array without a benefit), but it can be combined with any chain easily.
You can add a custom method to the Array prototype to make it available in a chain:
Array.prototype.filledOrDefault = function(defaultValue) {
return this.length ? this : defaultValue;
}
[1,2,3]
.filter(isDivisibleByTen)
.filledOrDefault('defaultValue');
This solution is not recommended because it modifies a global value (Array
) which is used by other scripts on a page.
Upvotes: 1
Reputation: 8274
I'll add a more verbose option here. This solution makes use of 3 pure functions, and then combines it in a pipeline. This is pretty typical of functional programming, and has the side benefit of being able to test the functions in isolation to make sure they do exactly what you want.
(As a sidebar other languages such as elixir make the chaining more syntactically pleasing, but I digress)
const defaultValue = "foobar";
const isDivisibleBy10 = n => n % 10 === 0;
const enforceDefault = numbers => numbers.length ? numbers : [defaultValue];
const unpackSingleton = numbers => numbers.length === 1 ? numbers[0] : numbers;
const pipeline = numbers =>
unpackSingleton(
enforceDefault(
numbers.filter(isDivisibleBy10)
)
)
console.log(pipeline([2])); // no matches so returns default
console.log(pipeline([20])) // one match so returns the item
console.log(pipeline([1, 20, 10, 3])) // general case
Upvotes: 0
Reputation: 147146
You could try reduce()
. This allows you to pass an initial value (the default return value) and then add values to the return array if they pass the test. So if no values pass the test, the function will return the default value.
console.log([1,21,30].reduce((t, v) => { return v % 10 === 0 ? (t = 'default' ? [v] : t.concat(v)) : t; }, 'default'))
console.log([1,21,35].reduce((t, v) => { return v % 10 === 0 ? (t = 'default' ? [v] : t.concat(v)) : t; }, 'default'))
Upvotes: 1
Reputation: 43880
Here's what I think you are looking for in one line, but if a result is false, filter() will return nothing. In Demo 1 filter()
is used. In Demo 2 map()
is used with a return of an arbitrary value of "default"
as the alternate return.
console.log([1, 21, 30].filter(a => a % 10 === 0));
console.log([1,21,30].map(a => a % 10 === 0 ? a : 'default'));
Upvotes: 1