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;
};
2 Answers 2
(削除) 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;
}, []);
};
-
\$\begingroup\$ First time using code review and this was a great answer. Thank you so much for taking the time to write that out. \$\endgroup\$Chase Norton– Chase Norton2017年11月12日 04:15:17 +00:00Commented Nov 12, 2017 at 4:15
-
\$\begingroup\$ @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? \$\endgroup\$James– James2017年11月12日 04:24:42 +00:00Commented Nov 12, 2017 at 4:24
-
-
\$\begingroup\$ @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. \$\endgroup\$James– James2017年11月12日 04:39:45 +00:00Commented Nov 12, 2017 at 4:39
-
1\$\begingroup\$ @ChaseNorton code would be more or less the same other than swapping out the
seen
object for aSet
. When adding to the set useseen.add(x)
and when checkingseen.has(x)
. \$\endgroup\$James– James2017年11月12日 20:36:13 +00:00Commented Nov 12, 2017 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.