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.
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+}'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:
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:
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 countryI 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")); }); }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
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 !!!"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"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
[[0 3 4] [1 2]] :”this gathers matches for each letter where there is more than 1 match”
[[-3 -1] [-1]] :”this finds the difference in each pair”
[[0 1] [1]] :”this identifies those differences where the abs() = 1 – the matches are right next to each other”
[0 1 1] :”this flattens the list”
2
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
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