Finding all pairs of elements in an array that sum to a target value

Is there a shorter way and does not involve nested for loops?

const checkIfSumFromTwoNumbers = (arrayOfNum, targetValue) => {
let found = [];
let result = [];

for (let value of arrayOfNum) {
if (found[targetValue - value] === true ) {
result.push({[arrayOfNum.indexOf(value)]: value, [arrayOfNum.indexOf(targetValue-value)]: targetValue - value});
}
found[value] = true;
}
return result;
};


No, each number requires a second pass to determine whether combined with an existing one it is a match - doesn't mean it can't be short though e.g.

const checkIfSumFromTwoNumbers = (arrayOfNums, targetValue) =>
arrayOfNums.reduce((matches, val) => {
const target = arrayOfNums.find(x => (val + x) === targetValue);
target && matches.push([val, target]);
return matches;
}, [])


I was actually ignorant to the fact your code actually works which means it can be done in one pass :) here's a slightly neater / more concise version of what you already have:

const checkIfSumFromTwoNumbers = (arrayOfNum, targetValue) => {
const seen = {};
return arrayOfNum.reduce((matches, val) => {
const delta = targetValue - val;
seen[delta] && matches.push([delta, val]);
seen[val] = true;
return matches;
}, []);
};

• First time using code review and this was a great answer. Thank you so much for taking the time to write that out. Nov 12 '17 at 4:15
• @ChaseNorton no worries, just realised that the current implementation would result in duplicates e.g. if your target value was 7 and you had an array of 1-5, 2+5 & 5+2 would match - presumably you wouldn't want this? Nov 12 '17 at 4:24
• A single pass solution is possible Nov 12 '17 at 4:26
• @wOxxOm actually, with a little tweak that solution would work. At the minute it just matches on the first sum - I may be able to adapt my own answer to be one pass now that I can see it has duplicates. Nov 12 '17 at 4:39
• @ChaseNorton code would be more or less the same other than swapping out the seen object for a Set. When adding to the set use seen.add(x) and when checking seen.has(x). Nov 12 '17 at 20:36

Since you mentioned shorter, the same array can be used for found and result:

const f = (a, t) => a.reduce((r, v) => (r[v - t] && r.push([t - v, v]), r[-v] = 1, r), [])

const f2 = (a, t) => a.reduce((r, v, i) =>
(r[v - t] + 1 && r.push({ [r[v - t]]: t - v, [i]: v }), r[-v] = i, r), [])

const a = [3, 1, 2, 2, 3, 4], l = console.log, j = JSON.stringify
l(j( f(a, 6) ))
l(j( f2(a, 6) ))

// .slice() can be added to the result to make a copy without the "hidden" items:
l(j({ ...f(a, 6)         }))
l(j({ ...f(a, 6).slice() }))

Hacky code golfed answers like this are probably not very appropriate on Code Review, so hopefully it's not too much against the rules. A bit of explanation:

In JavaScript, Array is actually an object that uses positive integer properties. For Example:

a = []
a[1] = 1
a.b = 'c'
a[-1] = -1
a[0.1] = 0.1
a[/./g] = /./g

console.log(a)      // [undefined, 1] - only the positive integer properties

console.log({...a}) // { "1": 1, "b": "c", "-1": -1, "0.1": 0.1, "/./g": /./g }

So this part r[-v] = 1 adds a key -v to the array, and r[v - t] && checks if the array has entry with key -(target - value), and if the entry's value evaluates to true.

Another part is the Comma Operator. In JavaScript result = (expresion1, expresion2) evaluates both expressions and returns the result of the last one.