3
\$\begingroup\$

Problem

Balanced number is the number that the sum of all digits to the left of the middle digit(s) and the sum of all digits to the right of the middle digit(s) are equal. The middle digit(s) should not be considered when determining whether a number is balanced or not.

If the number has an odd number of digits then there is only one middle digit, e.g. 92645 has middle digit 6; otherwise, there are two middle digits , e.g. 1301 has middle digits 3 and 0.

Given a number, find if it is balanced or not. Number passed is always Positive. Return the result as String.

My solution

I solved it. But I am not sure, how to fold the similarly looking code for odd and even lengths.

data ListLength a = ListLength {list :: [a], len :: Int} deriving Show

digs :: Integral x => x -> ListLength x
digs 0 = ListLength [0] 1
digs x = let
      helper :: Integral x => x -> [x] -> Int -> ListLength x
      helper 0 acc len = ListLength acc len
      helper n acc len = helper (n `div` 10) ((n `mod` 10) : acc) $ len + 1
  in
      helper x [] 0

balancedNum :: Int -> String
balancedNum n | n > 0 = let digits = digs n
                            middle = (len digits) `div` 2
                        in
                          if even (len digits) then
                            let (left, right) = splitAt (middle - 1) (list digits) in
                              if (sum left) == (sum $ drop 2 right) then
                                "Balanced"
                              else
                                "Not Balanced"
                          else
                            let (left, right) = splitAt middle (list digits) in
                              if (sum left) == (sum $ tail right) then
                                "Balanced"
                              else
                                "Not Balanced"
              | otherwise = error "Number must be positive"
\$\endgroup\$
3
\$\begingroup\$

Here my thoughts on your solution. But I'm also learning Haskell right now, so I'm not an expert..

You don't need the data type. You can use base 10 logarithm to get the number of digits. Like this:

(floor $ logBase 10 $ fromIntegral n) + 1

I like the fact that digs is tail recursive. It looks simpler without the data type:

digits :: Int -> [Int]
digits = digits_tr []
    where
        digits_tr :: [Int] -> Int -> [Int]
        digits_tr l 0 = l
        digits_tr l n = digits_tr (n `mod` 10 : l) (n `div` 10)

Why does balancedNum give a string? A boolean would be more natural. If you want to handle errors, why not use Maybe instead of error? Like in balancedNum :: Int -> Maybe Bool. Anyway according to the problem description you wouldn't need it: a negative number is just not balanced, so the function should just give False back.

Here is my solution:

balanced :: Int -> Bool
balanced n
    | n >= 0 = (sum $ take middle $ digits n) == (sum $ take middle $ reverse $ digits n)
    | otherwise = False
    where
        len = (floor $ logBase 10 $ fromIntegral n) + 1
        middle = if len `mod` 2 == 0 then len `div` 2 - 1 else len `div` 2
\$\endgroup\$
4
  • \$\begingroup\$ "You can use base 10 logarithm to get the number of digits." - this is a good option. On the other hand we can skip the logarithm calculation, using some memory for storage. We are traversing the list anyway. \$\endgroup\$
    – user4035
    Feb 10 '20 at 19:45
  • \$\begingroup\$ "Why does balancedNum give a string? A boolean would be more natural." - I agree, but this was the exercise condition. \$\endgroup\$
    – user4035
    Feb 10 '20 at 19:49
  • 1
    \$\begingroup\$ Oh, there is an error in this solution: balanced 56239814 returns False, while it it should return True. \$\endgroup\$
    – user4035
    Feb 10 '20 at 20:12
  • \$\begingroup\$ You're right: round after the logarithm was wrong (and didn't make sense). Now it should work. \$\endgroup\$ Feb 11 '20 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.