Может быть, это грубое и чрезмерно сложное решение, но я поставил перед собой задачу предложить ванильный JS, чисто функциональный подход для решения проблемы.
Кстати, есть библиотеки вроде Sanctuary или Ramda или многие другие, которые могли бы сохранить часть моего ответа.
У него есть только одна проблема: он проверяет все суммируемые комбинации (possibleSums
), но это плюс, так как можно распечатать все совпадения.Кроме того, есть someSumExists
, который просто проверяет, выводит ли possibleSums
одно или несколько совпадений.
С другой стороны, у него есть другая проблема: он основан на том факте, что входные данные не будут содержать повторяющиеся числа.
// ::: Combinators :::
// I :: a -> a -> a
const I = x => x
// T :: a -> (a -> a) -> a
const T = x => f => f (x)
// W :: a -> (a -> a -> a) -> a
const W = x => f => f (x) (x)
// ::: Non-generalized, partial Functor, Chain, Applicative Array-specific instances... :::
// map :: (a -> a) -> [a] -> [a]
const map = f => xs => xs.map (f)
// chain :: (a -> a) -> [a] -> [a]
const chain = f => xs => xs.reduce((o, x) => [...o, ...f (x)], [])
// ap :: [a -> b] -> [a] -> [b]
const ap = ms => m => chain (x => map (f => f(x)) (ms)) (m)
// lift2 :: [a -> c -> d] -> [a -> b] -> [b -> c] -> [d]
const lift2 = f => xs => ys => ap (map (f) (xs)) (ys)
// join :: [[a]] -> [a]
const join = chain (I)
// ::: Utils :::
// pipe :: [Any -> Any] -> Any -> Any
const pipe = xs => x => xs.reduce ((x, f) => f (x), x)
// any :: (a -> Boolean) -> [a] -> Boolean
const any = f => xs => xs.some (f)
// joinWith :: String -> [Any] -> [String]
const joinWith = sep => xs => xs.join (sep)
// length :: [Any] -> Number
const length = xs => xs.length
// equals :: a -> a -> Boolean
const equals = x => y => x === y
// not :: a -> Boolean
const not = x => x !== true
// possibleSums :: Number -> [[Number, Number, Number]]
const possibleSums = input =>
pipe ([
W,
T (lift2 (x => y => x !== y && input.includes (x + y) ? [[x, y, x + y]] : [])),
join
]) (input)
// someSumExists :: [Number] -> Boolean
const someSumExists = pipe ([
possibleSums,
length,
equals (0),
not
])
// printSums :: [[Number, Number, Number]] -> [String]
const printSums = pipe ([
map (([x, y, r]) => `${x} + ${y} = ${r}`),
joinWith ('\n')
])
// printPossibleSums :: [[Number, Number, Number]] -> String
const printPossibleSums = pipe ([ possibleSums, printSums ])
const input1 = [1, 2, 9, 4, 3]
const input2 = [2,7,12,6,8,20]
const input3 = [1, 2, 4, 9]
const output1 = printPossibleSums (input1)
const output1_ = someSumExists (input1)
const output2 = printPossibleSums (input2)
const output2_ = someSumExists (input2)
const output3 = printPossibleSums (input3)
const output3_ = someSumExists (input3)
console.log ('Input 1 has a case:', output1_)
console.log (output1)
console.log ('Input 2 has a case:', output2_)
console.log (output2)
console.log ('Input 3 has a case:', output3_)
console.log (output3)
Меньше шаблонного: Ramda !
Это тот же подход с использованием функций Рамды для сохранения некоторых строк кода:
const { map, join, length, equals, not, pipe, lift, unnest } = R
const W = x => f => f (x) (x)
const T = x => f => f (x)
const possibleSums = input =>
pipe (
W,
T (lift ((x, y) => x !== y && input.includes (x + y) ? [[x, y, x + y]] : [])),
unnest
) (input)
const someSumExists = pipe (
possibleSums,
length,
equals (0),
not
)
const printSums = pipe (
map (([x, y, r]) => `${x} + ${y} = ${r}`),
join ('\n')
)
const printPossibleSums = pipe (possibleSums, printSums)
const input1 = [1, 2, 9, 4, 3]
const input2 = [2,7,12,6,8,20]
const input3 = [1, 2, 4, 9]
const output1 = printPossibleSums (input1)
const output1_ = someSumExists (input1)
const output2 = printPossibleSums (input2)
const output2_ = someSumExists (input2)
const output3 = printPossibleSums (input3)
const output3_ = someSumExists (input3)
console.log ('Input 1 has a case:', output1_)
console.log (output1)
console.log ('Input 2 has a case:', output2_)
console.log (output2)
console.log ('Input 3 has a case:', output3_)
console.log (output3)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>