## 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");
}
```
7. Globules said

```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
"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
```