patternMinor
Find two numbers in a sorted array whose sum is closest to a given number
Viewed 0 times
sumnumberwhosearraynumbersclosesttwofindsortedgiven
Problem
Given a sorted array and a number x, find a pair in array whose sum is closest to x.
Here's my solution:
I'm mostly self-taught, so I would love to know in which ways my code is not according to common practice. More specifically:
Here's my solution:
import Data.List (minimumBy)
import Data.Ord (comparing)
closestPairSum :: (Num a, Ord a) => [a] -> a -> (a, a)
closestPairSum xs n = snd $ minimumBy (comparing fst) pairs
where
pairs = sums xs (reverse xs)
sums xxs@(x:xs) yys@(y:ys) = let sum = x + y in
if n < sum
then (sum - n, (x, y)) : sums xxs ys
else (n - sum, (x, y)) : sums xs yys
sums _ _ = []I'm mostly self-taught, so I would love to know in which ways my code is not according to common practice. More specifically:
- How can I more clearly align my
let-inandif-then-elseexpressions?
- I use an intermediate list of
(a, (a, a))tuples, which I'm not thrilled about. Is there a more elegant way to do this, without sacrificing performance?
- I'm on the fence about
sum xs (reverse xs)vssum xs $ reverse xs. Is this just considered nitpicking, or do people have a strong opinion about this?
- Would it make more sense to swap the parameters of this function? I have the feeling that
awould usually precede[a]with pointfree style in mind, but I'm not sure about this one.
- Anything else that I might not have thought of :)
Solution
The "intermediate array" takes no extra space due to lazy evaluation.
import Data.List (minimumOn)
minimumBy . comparing is minimumOn. Yes, swapping the parameters makes sense. Inline then and else once more. I wouldn't worry so much about constant factors - have you compiled it with -O2 and tested (eg with criterion)?import Data.List (minimumOn)
closestPairSum :: (Num a, Ord a) => a -> [a] -> (a, a)
closestPairSum n xs = minimumOn (abs . (n-) . uncurry (+)) pairs where
pairs = sums xs (reverse xs)
sums xxs@(x:xs) yys@(y:ys) = (x, y) : if n < x + y
then sums xxs ys
else sums xs yys
sums _ _ = []Code Snippets
closestPairSum :: (Num a, Ord a) => a -> [a] -> (a, a)
closestPairSum n xs = minimumOn (abs . (n-) . uncurry (+)) pairs where
pairs = sums xs (reverse xs)
sums xxs@(x:xs) yys@(y:ys) = (x, y) : if n < x + y
then sums xxs ys
else sums xs yys
sums _ _ = []Context
StackExchange Code Review Q#155039, answer score: 2
Revisions (0)
No revisions yet.