The Pairwise Algorithm Challenge

…Another solution with REDUCE… No code explanation needed … i hope …

function pairwise(arr, arg) {
  var indexSum = 0,
      len = arr.length,
      checkValue = NaN;
  if (len === 0) return indexSum;
  arr.reduce(function(acc,curr,index,array){
    for (var i = index; i < len; i++){
      //check for the same array's value
      if (checkValue === array[i]) {
        array[i] = NaN;
      };
      if (acc + array[i] === arg) {
        indexSum += (index-1)+i;
        checkValue = acc;
        array[i] = NaN;
        break; 
      };
    };
    acc = curr;
    return acc;
  });
  return indexSum;
}

pairwise([1,4,2,3,0,5], 7);

I would like to add another basic yet fast solution. It basically selects an element from the array, add it to the other elements in the array, if the sum is equal to the argument then it records the sum of the indices and deletes the pair from the array, hence replacing their value with “undefined”.

function pairwise(arr, arg) {
    var result = 0;
  for(var x = 0 ; x <arr.length; x++){
    for(var y = 0; y <arr.length; y++){
      if(x === y){
        break;
     }
      if(arr[x] + arr[y] === arg){
        result += x + y;
        delete arr[x];
        delete arr[y];
      } 
    }
  }
  return result;
}

you all can decide if this is basic, intermediate or advanced. I spent a long long time on this challenge and created this beastly code that I couldn’t even follow myself. took a break and came up with this extremely simple and, in my opinion, easy to follow solution.


function pairwise(arr, arg) {

  if (arr.length===0) { // arrays with no elements should not pass further through the code
    sum=0;
    return sum;
  }
  var indexArray=[];
  var first;
  // the for loop takes the index of variable first (two numbers a and b, first is 'a') and then
  // uses the arr.indexOf function to find the first index with the 'b' value that adds up to 
  // arg.
  // if the arr.indexOf returns -1, that means there is no element in the array with the 'b' value.
  // The last part of the if statement below makes sure that the 'a' value and the 'b' value
  // do not come from the same index in the array.
  for (i=0; i<arr.length; i++) {
    first=arr[i];
    var filtered= arr.indexOf(arg-first);
    if (filtered !==-1 && filtered !==i){
      // push the index pair who's elements add up to 'arg' to indexArray
      indexArray.push(i, filtered);
      // change the values in arr to a fictictious number so that they will never successfully
      // add up with another element to equal 'arg'
      arr.splice(i,1, -10);
      arr.splice(filtered,1,-10);
    }
  }
  // now sum the elements of indexArray.  Remember the elements of indexArray are actually
  // the indicies of 'arr'.
  var sum=indexArray.reduce(sumIt,0);
  function sumIt(a, b) {
    return a+b;
  }
  return sum;
}

For some reason, the first thing that comes to my mind when thinking of a replacement of a for loop is the Array.prototype.forEach method, so this working solution may be added to the pile:

// Credit goes to the advanced solution already provided on the FreeCodeCamp forum
function pairwise(arr, arg) {
var result=0;

arr.forEach(function(element,indexOfElement){
// It’s a good idea to always have a variable containing the search value before proceeding
var searchValue=arg-element;

if (arr.indexOf(searchValue)>-1 && arr.indexOf(searchValue)!=indexOfElement){
  result+=indexOfElement+arr.indexOf(searchValue);
  delete arr[indexOfElement];
  delete arr[arr.indexOf(searchValue)];
}

});

return result;
}

1 Like
function pairwise(arr, arg) {
  var noMut = Array.from(arr);                    //copy arr
  var indices = 0;                                //sum of indices
  var index;
  for(var i = 0; i < noMut.length -1; i++) {      //last element have not pair
    index = noMut.indexOf(arg - noMut[i], i + 1); //search index
    if(index !== -1) {
      indices += i + index;
      noMut[i] = noMut[index] = NaN;
    }  
  }
  return indices;
}
1 Like
function pairwise(arr, arg) {
  return arr.reduce(function(sum,cur,i,ar){
        for(var j=i+1;j<ar.length;j++){
          if(cur+ ar[j]=== arg){
             sum+=i+j;
            ar[j]=' ';
             break;
          }
      }

return sum;

},0);
}

2 Likes

Here’s another solution using reduce. No deleting or marking necessary.

 function pairwise(arr, arg) {
  var pairs = [];

  for (var i = 0; i < arr.length; i++) {
    for (var k = 0; k < arr.length; k++) {
      if (arr[i] + arr[k] == arg) {
        if (pairs.indexOf(i) < 0 && pairs.indexOf(k) < 0 && i != k) {
         pairs.push(i, k);
      }
    }
  }
}
if (pairs.length > 1) {
  return pairs.reduce(function(acc, val) {
    return acc + val;
  });
} else {
  return 0;
}
}

Here’s a simple solution to the problem.

function pairwise(arr, arg) {
  if (arr.length == 0){ return 0;};
  
  return arr.reduce(function(acc,val,idx){
               
                 for (var x = idx; x < arr.length; x++){ //Goes through array starting at current value used in reduce
                   
                   if ((arr[x+1] + arr[idx]) === arg) //checks if current value and next spot in array equal the argument 
                   {
                     if(!acc.includes(idx) && !acc.includes(x+1)) // checks if either of the indices are already stored. 
                                                                 //If so, it wont add them again- ensuring the smallest ones are saved
                     {
                       acc.push(x+1,idx);//adds each index singularly, to make it easy to sum up with reduce later on.
                     }
                   }
                 }
                 
                return acc;

             },[]).reduce(function(acc, val){return acc +val;});//sums up the indices to finish up the problem.
 
}  

As I looked at various solutions, now that I’m done that is, I realize it could’ve been easier to just remove or mark the indices that were used instead of an IF statement. :stuck_out_tongue:

1 Like

The ‘Relevant Links’ don’t appear to be linked to anything.

I used an object to store the indexes of the values which summed to the arg value instead of using indexOf or includes. The latter two still have to traverse the array, where the lookup on the object is only O[1]. Below is my original for loop version and then a functional version:

function pairwise(arr, arg) {
  let sum = 0;
  for (let used = {}, i=0; i<arr.length;i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] + arr[j] === arg && !used[i] && !used[j]) {
        used[i]=used[j] = true;
        sum += i+j;
      }
    }
  }
  return sum;
}

// functional solution;
function pairwise(arr, arg) {
  let used = {};
  return arr.reduce((sum,val,i,origArr) => origArr.reduce((sum2,val2,j) => {
    if (i !== j && val + val2 === arg && !used[i] && !used[j]) {
      used[i] = used[j] = true;
      sum2 += i+j;
    }
    return sum2;
  },sum),0);
}

did it this way

function pairwise(arr, arg) {
var newArr = [];
var sum = 0;
function checkIsThere (i,j) {
var place = 0;
for (x = 0; x < newArr.length;x++) {
if (i===newArr[x] || j ===newArr[x]) {
return false;
}

}
return true;

}
for (i = 0; i < arr.length-1; i++) {
for (j = i+1; j < arr.length; j++){

  if (arg === arr[i] + arr[j] && checkIsThere(i,j)) {
    newArr.push(i);
    newArr.push(j);
    sum+= i;
    sum+= j;
  }
}

}
return sum;
}

Got two short solutions, using .reduce (and one with .map as well). First attempt:

const pairwise = (arr, arg) => arr.map((e,i,a) => 
    a.indexOf(arg-e,i+1) > 0 || e === true ? a[a.indexOf(arg-e)] = true : false)
      .reduce((a,b,i)=> b ? a+=i : a,0);

Second attempt, without .map:

const pairwise = (arr, arg) => arr.reduce((p,c,i,a) => {
  let idx = a.indexOf(arg-c, i+1);
  return idx > 0 ? (c = a[idx] = NaN, p + i + idx) : p;
},0);

I wonder if I could compress it more, but it is 1.30 am and I need sleep.

1 Like

After reading some of these solutions, I’m worried that mine only works as far as the basic tests on the fcc map, but might not actually fulfill the specifications (for example the lowest combination of sums). My brain can’t stretch enough yet to figure out where this breaks down. Any thoughts/advice is appreciated.

function pairwise(arr, arg) {
  var sum=0;
  for (i=0;i<arr.length;i++){
    if (arr.indexOf(arg - arr[i]) !== -1 && arr.indexOf(arg - arr[i]) !== i){
      sum+= i + arr.indexOf(arg - arr[i]);
      arr[arr.indexOf(arg - arr[i])] = NaN;
      arr[i] = NaN;
    }
  }
  return sum;
}

I’m struggling to figure out why pairwise([0, 0, 0, 0, 1, 1], 1) should return 10. It’s not making a lot of sense to me. It seems like the value should be 4?

Why does the test say it should equal 10?

Also, doesn’t the highest available pair of indexes total 9?

I must be missing something. Or is this a bug in the tests?

The output should equal the sum of the indices whose values are summed to equal the second argument.

I.E., in the example you’re using, the first 0 is added to the first 1 in order to get the second argument, 1. Their indices are 0 and 4, 0 + 4 = 4

…then, the second 0 and the second 1 are similarly summed; their indices are 1 and 5, 1 + 5 = 6.

So, 0 + 4 + 1 + 5 = 10

oh, I’ve got it! Ok so I definitely misunderstood the instructions. I was too liberal with my exclusions, I thought every single instance of a duplicated pair would be discarded, but I understand now how I was wrong.

Thank you for pointing this out for me! :slight_smile:

One more solution…Calling function chackResult on array arr elements and if function returns true marking first element arr[i] as used. Function chackResult push sum of indecies in indexarr if result is equal to arg and element arr[i] is not allready used and marks second element as used. Finally reduce to sum all.


function pairwise(arr, arg) {
  var indexarr = [];
  
 for(var i=0; i<arr.length; i++ ){
   if( chackResult(arr[i])){
       arr[i] = 'used';  // prevent of using same arr.indexOf(numb1) in chackResult(numb1) loop  if  there is same value in arr
   }  
 }
   
   function chackResult(numb1){
     for(var i = arr.indexOf(numb1) + 1; i<arr.length; i++){ 
       if(numb1 + arr[i] === arg && arr[i]!== 'used'){   
         indexarr.push(arr.indexOf(numb1) + i);
         arr[i]= 'used';
         
         return true;     
       }
     }
   }
  
  return indexarr.reduce(function(a, b){
    return a+b;
},0);  
}

pairwise([0, 0, 0, 0, 1, 1], 1);

@dracoin My code was behaving erratically, and returning NaNs etc. Then I looked at your code and initialized searchVal, and for some reason, this fixed the problem…strange…? My code was exactly the same as yours, except for 1 thing - at first I didn’t bother to initialize searchValue, and instead just used arg - arr[element] inside the if statement. Anyway, here’s the code which failed…in case anyone wants to see indexes behaving erratically, inexplicably, which is what this scripting challenge is about…

function pairwise(arr, arg) {
  var sumOfIdx = 0;
  for (var i = 0; i < arr.length; i++) {
    if (arr.indexOf(arg - arr[i]) !== -1 && arr.indexOf(arg - arr[i]) !== i) { //i.e. the ith element has at least 1 pair
      sumOfIdx += i + arr.indexOf(arg - arr[i]);
      arr[i] = "-";
      arr[arr.indexOf(arg - arr[i])] = "-";
    }
  }  
  return sumOfIdx;
}

I don’t understand why pairwise([0, 0, 0, 0, 1, 1], 1) should return 10. The rules state that if “multiple pairs are possible that have the same numeric elements but different indices, return the smallest sum of indices.” None of the solutions above seem to be taking that rule into account.

Maybe I’m misinterpreting the rule?

0 0 0 0 1 1 // values
0 1 2 3 4 5 // indices
0       1   //= 4 * wouldn't this be the pair with the smallest sum of indices?
  0     1   //= 5 
    0   1   //= 6
      0 1   //= 7

0         1 //= 5 
  0       1 //= 6 
    0     1 //= 7
      0   1 //= 8
function pairwise(arr, arg) {
  
  var indices = [];
  
  for(var i=0; i<arr.length-1; i++){
    for(var j=i+1; j<arr.length; j++){
      if(indices.indexOf(i) > -1){
        break;
      }
      if(indices.indexOf(j) > -1){
        continue;
      }
      if(arr[i] + arr[j] === arg){
        indices.push(i, j);
      }
    }
  }
  
  if(indices.length === 0){
    return 0;
  }
  
  return indices.reduce(function(sum, value){
    return sum + value;
  });
      
}