Here we go again! This time, we are going to be working on Pairwise. This is a tough one for beginners, but do not worry, let’s go slow and get this beast under control and understand the logic behind the code we’ll be writing.
We must write a function that takes two arguments, an array (of numbers) and a number. The function must return the sum of the indices of those elements within the array that sum up to the second argument when paired. Big words, no better way to understand than examples:
pairwise([7, 2, 3], 5); //-> 2 + 3 = 5, we sum the index of 2 (1, remember 0 indexing) and 3 (2), answer is 1 + 2 = 3
Not only that, we must also take care of the following:
- We can only use each element once.
- If multiple sums are possible, use the lowest.
Notice how we are using the index of the first 1 to get the answer in the following example:
pairwise([1, 1, 1, 5], 6); //-> 1 + 5 = 6, we sum the index of 1 (0, always use the lowest sum!) and 5 (3), answer is 0 + 3 = 3
Let’s get to it then, let’s start with the bare bones, and make sure that we are getting an array with something in it and a number; if not, return 0 (zero). We’ll also create an empty array for the result to be stored (BUT we must return a number! -you may say, hold on, we’ll get to that):
function pairwise(arr, arg) { if (arr.length === 0 || typeof arg !== 'number') { return 0; } var result = []; // Do some magic and return something! }
Why an array for the result? It will become clear in a bit, but let’s just say that it’s the place were we’ll store the indices for the numbers that sum up to the second argument, and that we’ll sum them up before we return them.
Let’s start by populating this array. In every case, there is multiple ways of achieving the same result; I’ll show you the solution that I deem most comprehensive and easy to understand. We are going to be using two nested for loops. This way, we start off with the first element, and then sum every item in the array to it. We also need to make sure that we do not add a number to itself, here’s what it looks like:
function pairwise(arr, arg) { if (arr.length === 0 || typeof arg !== 'number') { return 0; } var result = []; for (var i = 0; i < arr.length; i++) { // Outer for loop for (var j = 0; j < arr.length; j++) { // Inner loop if (i !== j) { // We make sure that the index is different, so that we don't add a number to itself. console.log(arr[i] + arr[j]); // Log the sum } }; }; }
This function will print the sum of every item in the array to every other item. Now that we have the sums in our hands, let’s do something with them! How about adding their indices to the result array when the sum is equal to the second argument? Sounds good, let’s do it. Instead of creating a new if statement, we’ll use the one we created in the previous step, and take advantage of the logical AND operator (&&):
function pairwise(arr, arg) { if (arr.length === 0 || typeof arg !== 'number') { return 0; } var result = []; for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr.length; j++) { if (i !== j && arr[i] + arr[j] === arg) { // This time, we also check if the sum is equal to the second argument result.push(i, j); // We push both indices to the result array. break; // Once added, stop looking, since we don't want to get another possible sum that is higher. We are told to use the lowest! } }; }; }
Looking better, but we got a few flaws. We need to check if we have already used a number before adding it to the results. We are going to use the indexOf method (see how indexOf is used here) to check if we have already added these indices to the result array before. If indexOf finds a match, it will return it’s position, if not, it will return -1. Since not all browsers behave the same way, we’ll just check if the returned number is less than 0:
function pairwise(arr, arg) { if (arr.length === 0 || typeof arg !== 'number') { return 0; } var result = []; for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr.length; j++) { if (i !== j && arr[i] + arr[j] === arg && result.indexOf(i) < 0 && result.indexOf(j) < 0) { result.push(i, j); break; } }; }; }
Now we’re talking! We are ready to return something this time around, so let’s add every item in the result array and return it. Let’s use the Array.prototype.reduce() method for this task (you can see reduce in action here and here):
function pairwise(arr, arg) { if (arr.length === 0 || typeof arg !== 'number') { return 0; } var result = []; for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr.length; j++) { if (i !== j && arr[i] + arr[j] === arg && result.indexOf(i) < 0 && result.indexOf(j) < 0) { result.push(i, j); break; } }; }; return result.reduce(function(a, b) { return a + b; }); }
We are done! If you are still unsure as to how does the function work, please, shot me an email, ping me on twitter or post a comment below. Happy coding!