Doubled Letters

July 9, 2019

We have a fun little exercise on a lazy summer Tuesday:

Given a list of words, remove from the list those words that have two adjacent identical letters. For instance, given “Now is the time for all good men to come to the aid of their country” the program should remove the words “all” and “good”.

Your task is to write a program to remove words with doubled letters from a list of words. 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.

Pages: 1 2

10 Responses to “Doubled Letters”

  1. James Curtis-Smith said

    Perl to the rescue again – just a simple oneliner – that splits the words apart and joins them back together again after stripping double letters.

    echo "Now is the time for all good men to come to the aid of their country" | \
      perl -nE 'say join q( ), grep { m{\S} && ! m{(\w)\1} } split m{\s+}'
    
  2. Daniel said

    Here’s a case-sensitive solution in Python.

    [sourceccode lang=”python”]
    def remove(s):
    return ‘ ‘.join(w for w in s.split() if all(c1 != c2 for c1, c2 in zip(w, w[1:])))

    s = ‘Now is the time for all good men to come to the aid of their country’
    print(remove(s))
    [/sourcecode]

    Output:

    Now is the time for men to come to the aid of their country
    
  3. Daniel said

    My spelling was wrong in the markup. Here it is again, hopefully formatted correctly this time.

    def remove(s):
        return ' '.join(w for w in s.split() if all(c1 != c2 for c1, c2 in zip(w, w[1:])))
    
    s = 'Now is the time for all good men to come to the aid of their country'
    print(remove(s))
    

    Output:

    Now is the time for men to come to the aid of their country
    
  4. mcmillhj said

    Simple one-liner in perl5:

    say join ' ', grep { !/(\w)\1/ } 
                     split /\s+/, "Now is the time for all good men to come to the aid of their country"
    # Now is the time for men to come to the aid of their country
    
  5. matthew said

    I need some C++ practice:

    #include <string>
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <regex>
    
    int main() {
      std::remove_copy_if(std::istream_iterator<std::string>(std::cin),
                          std::istream_iterator<std::string>(),
                          std::ostream_iterator<std::string>(std::cout,"\n"),
                          [](auto s) {
                            return std::regex_search(s,std::regex("(.)\\1"));
                          });
    }
    
    $ g++ -Wall -std=c++14 filter.cpp -o filter
    $ echo "Hubble, bubble, toil and trouble" | ./filter
    toil
    and
    trouble
    
  6. Bill Wood said

    Rust version

    use itertools::*; // 0.8.0
    
    fn has_dup(s: &str) -> bool {
        let mut prev = ' ';
        s.chars().any(|c| if c == prev { true } else { prev = c; false })
    }
    
    fn rem_adjacent(s: &str) -> String {
        s.split(" ").filter(|&w| ! has_dup(w)).join(" ")
    }
    
    fn main() {
        assert_eq!(rem_adjacent("Now is the time for all good men to come to the aid of their country"),
            "Now is the time for men to come to the aid of their country");
    }
    

    Playground https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4ec2d8d1c446e288febe489ed208e0d7

  7. Globules said

    A Haskell version.

    import Data.Char (isLetter, toLower)
    import Data.List (group)
    
    doubleLetter :: String -> Bool
    doubleLetter (x:y:_) = isLetter x && x == y
    doubleLetter _       = False
    
    hasDoubleLetters :: String -> Bool
    hasDoubleLetters = any doubleLetter . group . map toLower
    
    remdoublet :: String -> String
    remdoublet = unwords . filter (not . hasDoubleLetters) . words
    
    main :: IO ()
    main = do
      putStrLn $ remdoublet "Now is the time for all good men to come to the aid \
                            \of their country"
      putStrLn $ remdoublet "aAa xyx !!!"
    
    $ ./remdoublet
    Now is the time for men to come to the aid of their country
    xyx !!!
    
  8. Steve said

    Klong version 20190209

    Program:
      1 :" Doubled Letter"
      2
      3 :" Start and end points for each substring(substr#; string)"
      4 sub::{[spcs]; spcs::y?" "; :[x=0; 0,(spcs@x)-1 :|x=#spcs; ((spcs@x-1)+1),(#y)-1;     ((spcs@x-1)+1),(spcs@x)-1]}
      5
      6 :" Extract substring(substr#; string)"
      7 subst::{[b e]; b::sub(x; y); e::b@1; b::b@0; (1+e-b)#(b_y)}
      8
      9 :" Find double letter for a single letter"
     10 dbl::{[f]; f::0; {[len lst]; len::#lst::x; (len-1){[dif]; dif::(lst@(x+1))-lst@x;     f:::[dif=1; 1; 0]; x+1}:*0}(x);f}
     11
     12 :" Find double letter for a word"
     13 dblw::{(+/{dbl(x)}'=x)>0}
     14
     15 :"Print non-double words in string"
     16 go::{[sent spcs str]; sent::""; spcs::(str::x)?" "; (1+#spcs){word::subst(x; str)    ; :[~dblw(word); sent::sent,word," "; 0]; x+1}:*0; (-1)_sent}
    
    Execution:
            ]l dbl_ltrs
    loading "./dbl_ltrs.kg"
            go("this is a google, facebook, twitter, internet")
    "this is a internet"
            go("Now is the time for all good men to come to the aid of their country")
    "Now is the time for men to come to the aid of their country"
    
  9. Jim said

    Klong version 20190209

    [sourcecode lang="css"]

    Code:
    :” Doubled Letter”

    :” Find double letter for a word”
    dblw::{[l word]; l::[]; word::x; {x}'{:[1<#x; l::l,,x; 0]}’=word; :[0=#l; 0; 0<+/,/{{1=#x}’-:’x}’l]}

    :”Print non-double words in string”
    go::{[n s w]; s::””; {~@n::x?” “}{s:::[dblw(w::(n::n@0)#x); s; s,w,” “]; (n+1)_x}:~x,” “; (-1)_s}

    Run:

    Logic:
    Klong is 0-based. The = operator identifies the unique matches and puts each identical match in a list
    =”googgle”
    [[0 3 4] [1 2] [5] [6]] :” g occurs in positions 0/3/4;
    o occurs in positions 1/2;
    l occurs in position 5; and
    e occurs in position 6

        l::[]; {x}'{:[1<#x; l::l,,x; 0]}'="googgle"; l
    

    [[0 3 4] [1 2]] :”this gathers matches for each letter where there is more than 1 match”

        {-:'x}'l
    

    [[-3 -1] [-1]] :”this finds the difference in each pair”

        {{1=#x}'-:'x}'l
    

    [[0 1] [1]] :”this identifies those differences where the abs() = 1 – the matches are right next to each other”

        ,/{{1=#x}'-:'x}'l
    

    [0 1 1] :”this flattens the list”

        +/,/{{1=#x}'-:'x}'l :"this adds the number of matches next to each other"
    

    2

        0<+/,/{{1=#x}'-:'x}'l :"this determines if there is at least 1 such match"
    

    1

    {~@n::x?” “}{s:::[dblw(w::(n::n@0)#x); s; s,w,” “]; (n+1)_x}:~x,” ”
    x?” ” – creates list of matches to a space in string
    n::x?” ” – sets n equal to that list
    @n – Check that it is an atom (empty list)
    ~@n – Checks that it is NOT an atom
    {~@n::x?” “} – while the string is not empty
    n@0 – get first position of space in string
    n=n@0 – set n equal to first position of space in string
    w::(n::n@0)#x – get word up to first spaces in atom and set w to it
    dblw(w…) – if w has spaces, return 0; otherwise return 1
    :[dblw(…; s; s,w,” “] – if w has spaces, set s = s; otherwise append w and a space to the end of string
    (n+1)_x – set string for the next iteration equal to the string without the leading word and space
    {~@…}{s::…}:~x” ” – while the string is not empty, identify the next word, append it to new string if no double letters and get next string. First string = input appended to space

  10. James said

    Klong version 20190209

    
    Code:
    :" Doubled Letter"
    
    :" Find double letter for a word"
    dblw::{[l word]; l::[]; word::x; {x}'{:[1<#x; l::l,,x; 0]}'=word; :[0=#l; 0; 0<+/,/{{1=#x}'-:'x}'l]}
    
    :"Print non-double words in string"
    go::{[n s w]; s::""; {~@n::x?" "}{s:::[dblw(w::(n::n@0)#x); s; s,w," "]; (n+1)_x}:~x," "; (-1)_s}
    
    Run:
            go("this is the time for all good men to come to the aid of their country")
    "this is the time for men to come to the aid of their country"
    
    Logic:  I enjoy seeing how different languages approach the same problem.  Klong is an array language and approaches differently than other languages.
    
    Klong is 0-based.  The = operator identifies the unique matches and puts each identical match in a list
            ="googgle"
    [[0 3 4] [1 2] [5] [6]] :" g occurs in positions 0/3/4; 
                                      o occurs in positions 1/2;
                                      l occurs in position 5; and
                                      e occurs in position 6
    
            l::[]; {x}'{:[1<#x; l::l,,x; 0]}'="googgle"; l
    [[0 3 4] [1 2]] :"gathers matches for each letter where there is more than 1 match"
    
            {-:'x}'l
    [[-3 -1] [-1]] :"finds the difference in each pair"
    
            {{1=#x}'-:'x}'l
    [[0 1] [1]] :"identifies those differences where the abs() = 1 - the matches are right next to each other"
    
            ,/{{1=#x}'-:'x}'l
    [0 1 1] :"flattens the list"
    
            +/,/{{1=#x}'-:'x}'l
    2 :"adds the number of matches next to each other"
    
            0<+/,/{{1=#x}'-:'x}'l
    1 :"determines if there is at least 1 such match"
    
    [n s w]                 - Create local variables
    s::""                   - Set new sentence variable = ""
    
    {~@n::x?" "}{s:::[dblw(w::(n::n@0)#x); s; s,w," "]; (n+1)_x}:~x," "
                            - while the string is not empty, identify the next word, append it to new string if no double letters and get next string.  First string = input appended to space
    x?" "                   - creates list of matches to a space in string
    n::x?" "                - sets n equal to that list
    @n                      - Check that it is an atom (empty list)
    ~@n                     - Checks that it is NOT an atom
    {~@n::x?" "}            - while the string is not empty
    n@0                     - get first position of space in string
    n=n@0                   - set n equal to first position of space in string
    w::(n::n@0)#x           - get word up to first spaces in atom and set w to it
    dblw(w...)              - if w has spaces, return 0; otherwise return 1
    :[dblw(...; s; s,w," "] - if w has spaces, set s = s; otherwise append w and a space to the end of string
    (n+1)_x - set string for the next iteration equal to the string without the leading word and space
    

Leave a comment