Reputation: 469
In the process of learning functional programming, I am trying to refactor the following code using map, filter, and/or reduce.
I see that I can deal with the conditional using the filter method, but don't know how to handle the repeated assignment so I can avoid use of a for loop.
I am thinking that I would use the map method to handle the diff assignments, and chain a filter method that would deal with the conditional. Am I on the right track?
Would someone be kind enough to refactor the following code in the functional paradigm and explain. Thanks.
This function finds the first non-consecutive number in an array.
function firstNonConsecutive (arr) {
var diff = 0;
for(var i = 0; i < arr.length; i++) {
diff = arr[i+1] - arr[i];
if(diff > 1) {
return arr[i+1];
}
}
return null;
Upvotes: 2
Views: 87
Reputation: 135227
Recursion by mathematical induction -
a
, or the second element, b
, are null, return undefineda
, nor the second element, b
are null. If b
is consecutive to a
, return the recursive result of the smaller problema
, nor the second element, b
, are null and b
is not consecutive to a
. Return the answer, b
.const firstNonConsecutive = ([ a, b, ...more ]) =>
a == null || b == null
? undefined // 1
: b === a + 1
? firstNonConsecutive([ b, ...more ]) // 2
: b // 3
console.log(firstNonConsecutive([ 4, 5, 6, 8, 9, 10 ]))
// 8
console.log(firstNonConsecutive([ 7, 8, 9, 10, 13, 14 ]))
// 13
console.log(firstNonConsecutive([ 99 ]))
// undefined
console.log(firstNonConsecutive([]))
// undefined
Upvotes: 0
Reputation: 4912
You want to use Array.find
, not .map
, .filter
, or .reduce
. You could find a way to use those, but they waste time because they don't return as soon as the first match is found.
Here are some progressively more verbose solutions to help you understand how the first one works.
The second is the most functional, because it's declarative unlike the first.
array.find(nonConsecutive)
reads close to plain English and declares what you want to do, leaving the imperative implementation details hidden away inside the nonConsecutive
function.
const array = [1, 2, 3, 4, 5, 6, 7, 9, 10];
console.log(
array.find((n, i) => i && n != array[i - 1] + 1) // 9
);
const nonConsecutive = (n, i, arr) => i && n != arr[i - 1] + 1;
console.log(
array.find(nonConsecutive) // 9
);
console.log(
array.find(function (number, index) { // we don't need third "array" argument because the array is already in scope.
if (index == 0) return false; // if index is zero, return. Otherwise, next line would access index -1.
if (number != array[index - 1] + 1) return true; // if number is not equal to the the previous number, plus one, it's not consecutive. Return it.
return false; // if we reach this line than the number must be consecutive, so return false.
}) // 9
);
Upvotes: 0
Reputation: 14179
If you are looking into fp, then also recursion would find a good application here:
const firstNonConsecutive = (list) => {
if (!list.length) {
// list is empty, not found
return -1;
}
const [head, ...tail] = list;
const [n] = tail;
if (n - 1 !== head) {
// found
return n;
}
// yet another round
return firstNonConsecutive(tail);
};
console.log(
firstNonConsecutive([1, 2, 3, 4, 5, 6, 7, 9, 10]),
);
Upvotes: 0
Reputation: 1012
Consider using Array.find https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find, like most functional array functions it takes a callback/predicate that takes 3 parameters, the item, the index and the whole array. With this you can look ahead/behind in the same way you currently do. Like this:
function firstNonConsecutive2(arr) {
return arr.find((item, index, array) => {
const diff = array[index - 1] - item; // Use index -1 to look behind instead of ahead since we want to return/find the item that is non-consecutive
return diff === 0; // I think this was a small bug in your version which worked if the numbers were incrementing only
});
}
In the first iteration of the find "loop" it'll try to diff undefined
with for example 1
, which is NaN
, NaN
is not equal to 0 so it keeps searching. Next it'll try maybe 1
and 2
so diff
becomes -1
so it keeps searching. Until it reaches for example 5
and 5
, which diffs to 0
so the find predicate is now true, so it will return the second 5
since that is the current item, we're looking behind us by using index - 1
.
Let me know if you want further explanation of something!
Upvotes: 1