1
\$\begingroup\$

I'm trying to write function, that replace digits at some positions in number.

For example f 91521 [3,4] -> [91001,91111,91221,91331,91441,91551,91661,91771,91881,91991]

It's behavior like 91**1 -> ..., so I named it as a 'whitemask'.

Question 1: is "whitemask" a normal and adequately name for that function?

After that I've formulated that 'whitemask' function.

sublists :: (Eq a) => [a] -> [[a]]
sublists list = [x | x <- subsequences list, x /= []]

numbers :: [Int]
numbers =  take 10 [0..]

numLength :: Integer -> Int
numLength = length . show

decreaseList :: Num a => [a] -> a -> [a]
decreaseList = (\a b c -> map (a c) b) (flip (-))

listToNum :: [Int] -> Integer
listToNum digits = toInteger $ foldl1 (\x y -> x*10 + y) digits

numToList :: Integer -> [Int]
numToList x = map digitToInt $ show x

remove :: [Int] -> [Int] -> [[Int]]
remove [] x = [x]
remove (x:xs) list = putted : remove (decreaseList xs x) unputted
    where [putted,unputted] = (\(x,y) -> [init x,y]) $ splitAt x list

sew :: [[a]] -> a -> [a]
sew list sewer = foldr1 (\x y -> x ++ [sewer] ++ y) list

whitemask :: Integer -> [Int] -> [Integer]
whitemask num places =  filter (\x -> numLength x == numLength num ) $ map (listToNum . sew (remove places (numToList num))) numbers

But in context of all problem where that function might be used I figured out, that I need only fix-length answers. For examples, it works like

> whitemask 75148 [1,3,4]
[15118,25228,35338,45448,55558,65668,75778,85888,95998]

and answer isn't contain '5008' element.

Question 2: is that fix-length filtering 'whitemask' function's business? Or it would be better to return all possible variants and filtering them if it really needed?

When I've started to use that function in complicated iterates ways I figured out that it's might do some unnecessary and superfluous calculations.

Question 3: how can I refactor 'whitemask' function with less-usage folds maps and recursions?

Any cosmetics and style advices are appreciated.

ps: did I select the right place to asking for? (question could be migrated to SO actually)

UPD: I figured out that sew can be written much easier.

sew list sewer = concat $ intersperse [sewer] list
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I didn't thought about the algorithm itself, but shortened the code a little bit:

decreaseList :: Num a => [a] -> a -> [a]
decreaseList b c = map (subtract c) b  

listToNum :: [Int] -> Integer
listToNum = toInteger . foldl1 ((+).(*10)) 

numToList :: Integer -> [Int]
numToList = map digitToInt . show

remove :: [Int] -> [Int] -> [[Int]]
remove [] x = [x]
remove (x:xs) list = let (putted, unputted) = splitAt x list
                     in (init putted) : remove (decreaseList xs x) unputted

sew :: [[a]] -> a -> [a]
sew list sewer = foldr1 ((++).(++[sewer])) list

whitemask :: Integer -> [Int] -> [Integer]
whitemask num places =  let  list = map (listToNum . sew (remove places (numToList num))) [0..9]
                        in filter (((==) `on` length . show) num) list

I think there is still room for improvement...

[Edit]

A shorter version:

whitemask :: Integer -> [Int] -> [Integer]
whitemask num places = map (listToNum . replace)  [0..9]  where
  replace digit = foldr ((:).findDigit) [] $ zip (numToList num) [1..] where
    findDigit (d,i) | i `elem` places = digit
                    | otherwise = d

listToNum :: [Int] -> Integer
listToNum = toInteger . foldl1 ((+).(*10))

numToList :: Integer -> [Int]
numToList = map digitToInt . show

[Edit]

A shorter version, with fixed-length filtering:

whitemask :: Integer -> [Int] -> [Integer]
whitemask num places = map replace digits  where
  digits = if 1 `elem` places then [1..9] else [0..9]
  toList = map digitToInt $ show num
  replace digit = foldl toNum 0 $ zip toList [1..] where
    toNum r (d,i) = 10*r + (fromIntegral $ if i `elem` places then digit else d)

I can't promise that I'll end up with a one-liner, though...

To your questions:

  1. Depends on the context. If you are unsure about the name, just explain the function with a comment.
  2. Depends if you would ever need unfiltered output. In this case that looks pretty unlikely, so I would include the filtering.
  3. See above.
\$\endgroup\$

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.