Removing Spaces

February 11, 2020

We have a simple task today, with dozens of potential solutions:

Write a program to remove all spaces from a string.

Your task is to write a program to remove all spaces from a string. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

12 Responses to “Removing Spaces”

  1. Pascal Bourguignon said

    (defun remove-all-spaces (string) (remove #\space string))

    (remove-all-spaces “Hello World !”) ; –> “HelloWorld!”

  2. Zack said

    Nice drill! Although there are more interesting ways of solving this, I’d go with the simplest one, using Julia:
    RemoveSpaces(x::String) = join(split(x, ” “))

    Fortunately, it doesn’t need any packages either.

  3. d1rge said

    sed ‘s/ //g’

    Am I cheating?

  4. Steve said

    Klong version

    
            word::"  Programming  Praxis  "
    "  Programming  Praxis  "
    
            {" "=$x}'word :"Flag if position = space"
    [1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1]
    
            {~" "=$x}'word  :"Flag is position not space"
    [0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0]
    
            &{~" "=$x}'word  :"Only include position number of no spaces"
    [2 3 4 5 6 7 8 9 10 11 12 15 16 17 18 19 20]
    
            word@&{~" "=$x}'word  :"Get value for each of those positions"
    "ProgrammingPraxis"
    
  5. Daniel said

    Here’s a solution in Python.

    def remove_char(s, char=' '):
        return s.replace(char, '')
    
    print(remove_char('p r o g r a m m i n g _ p r a x i s'))
    print(remove_char('programming praxis', 'p'))
    

    Output:

    programming_praxis
    rogramming raxis
    
  6. matthew said

    Haskell one-liner:

    Prelude Control.Monad> f = (>>= ap (flip replicate) (fromEnum . (' ' /=)))
    Prelude Control.Monad> f "the quick brown fox"
    "thequickbrownfox"
    
  7. Daniel said

    Here’s a solution in C.

    #include <stdio.h>
    #include <stdlib.h>
    
    void remove_char(char* s, char c) {
      char* p1 = s;
      char* p2 = s;
      while (1) {
        *p1 = *p2;
        if (*p2 == '\0') break;
        if (*p1 != c) ++p1;
        ++p2;
      }
    }
    
    int main(int argc, char* argv[]) {
      if (argc != 3) return EXIT_FAILURE;
      remove_char(argv[2], *argv[1]);
      printf("%s\n", argv[2]);
      return EXIT_SUCCESS;
    }
    

    Example usage:

    $ ./a.out ' ' 'p r o g r a m m i n g _ p r a x i s'
    programming_praxis
    
    $ ./a.out 'p' 'programming praxis'
    rogramming raxis
    
  8. matthew said

    An even more monadic one-liner:

    Prelude Control.Monad> f = (>>= \a -> case a of ' ' -> mzero; _ -> return a)
    Prelude Control.Monad> f "the quick brown fox"
    "thequickbrownfox"
    
  9. matthew said

    Or even:

    > import Control.Conditional
    > import Control.Monad
    > import Control.Applicative
    > f = (>>= liftA3 if' (==' ') (const mzero) return)
    > f "the quick brown fox"
    "thequickbrownfox"
    
  10. matthew said

    Last one – there is an ‘ifM’ function in Control.Conditional that lifts if’ (the conditional function) into a monad (in this case, the function monad, so ‘ifM f g h’ is ‘if f x then g x else h x’ and I don’t need Control.Applicative any more. The bind, mzero and return are in the list monad (so are concatMap, empty list, and \x->[x] respectively):

    Prelude Control.Conditional Control.Monad> f = (>>= ifM (==' ') (const mzero) return)
    Prelude Control.Conditional Control.Monad> f "the quick brown fox"
    "thequickbrownfox"
    
  11. Steve said

    @matthew: Can you explain your Haskell programs? Amazing what 1 line can do! Thanks, Steve

  12. matthew said

    @Steve: Here’s an attempt at an explanation (I might post this elsewhere, so grateful for any comments):

    In Haskell, a string is just a list of characters, so one way of doing this is to map a function over that list. What should that function be? It can’t just be a map from Char to Char – what would it do for the space character? A possibility, since we are already dealing with lists is to use a function Char->[Char], ie. take a Char and return a list of Chars:

    f s = concat (map g s) where
      g ' ' = []
      g c = [c]
    
    f "the quick brown fox"
    "thequickbrownfox"
    

    Now let’s start the fooling around.

    First of all, let’s go point free. f is just applying two functions (concat and map g) to its argument, so we can rewrite as a composition:

    f = concat . map g where
      g ' ' = []
      g c = [c]
    

    Now, it would be good to get rid of that auxiliary function, one way would be to use a lambda:

    f = concat . map (\c -> case c of ' ' -> []; _ -> [c])
    

    or:

    f = concat . map (\c -> if c == ' ' then [] else [c])
    

    Alternatively, we can use an ‘Iverson bracket’ and use the numeric value of the boolean test as a parameter to ‘replicate’, ‘replicate n a’ makes n copies of a, and ‘fromEnum False’ is 0, ‘fromEnum True’ is 1:

    f = concat . map (\c -> replicate (fromEnum (' ' /= c)) c)
    

    and we should recognize that ‘concat . map f’ is just a monadic bind: (>>= f):

    f = (>>= (\c -> replicate (fromEnum (' ' /= c)) c))
    

    Now that lambda is of the form: \c -> (f (g c) c) which is almost the form of the S-combinator:

    s f g x = (f x)(g x)
    

    and if we change the parameter order of replicate we get exactly this form:

    f = (>>= s (flip replicate) (fromEnum . (' ' /=)))
    

    Haskell doesn’t have an S combinator as such, but the Applicative operator ‘ap’ is equivalent to S in the function monad, so finally we end up with:

    f = (>>= ap (flip replicate) (fromEnum . (' ' /=)))
    

    That’s nice, but the use of replicate is a bit obscure, let’s go back to the case form:

    f = (>>= \c -> case c of ' ' -> []; _ -> [c])
    

    or

    f = (>>= \c -> if c == ' ' then [] else [c])
    

    Being Haskell programmers we can’t help noticing that [] and [c] are both monadic – [] is just ‘monadic zero’ in the list monad, and in the same monad, [c] is ‘return c’, so now we have:

    f = (>>= \c -> case c of ' ' -> mzero; _ -> return c)
    f = (>>= \c -> if c == ' ' then mzero else return c)
    

    Not much more to be done with the ‘case’ form, but we can make use of the laziness of Haskell to rewrite the ‘if’ form: we can write ‘if’ as a function:

    if' x y z = if x then y else z
    

    and laziness ensures that only one of y and z get evaluated, so we have:

    f = (>>= \c -> if' (c == ' ') mzero (return c))
    

    or:

    f = (>>= \c -> if' (c == ' ') ((const mzero) c) (return c))
    

    where const is just the K-combinator:

    const x y = x
    

    so what I want is a “functional if”:

    if'' f g h x = if' (f x) (g x) (h x)
    
    f = (>>= if'' (== ' ') (const mzero) return)
    

    and this can be done by “lifting” if’ into the function Monad (though actually, this is an Applicative operation):

    import Control.Applicative
    f = (>>= liftA3 if' (==' ') (const mzero) return)
    

    or, even better, use the ifM function directly (defined in Control.Conditional):

    > import Control.Conditional
    > :t ifM
    ifM :: (ToBool bool, Monad m) => m bool -> m a -> m a -> m a
    
    f = (>>= ifM (==' ') (const mzero) return)
    

    For a final monadic flourish, we can observe that ‘const’ itself is just ‘return’ in the function monad and we get:

    f = (>>= ifM (==' ') (return mzero) return)
    

    Now f works for other instances of Monad (or rather MonadPlus, since we require mzero), for example Maybe and IO:

    > map f [Nothing,Just ' ',Just 'a']
    [Nothing,Nothing,Just 'a']
    
    > f getChar
    <types space> 
     ^J*** Exception: user error (mzero)
    > f getChar
    <types 'a'>
    a'a'
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: