Discussion:
[Tutor] Messy - Very Messy string manipulation.
Vusa Moyo
2015-10-28 15:09:59 UTC
Permalink
Hi Guys,

I've written a script to remove vowels from a string/sentence.

the while loop I'm using below is to take care of duplicate vowels found in
a sentence, ie

anti_vowel('The cow moos louder than the frog')

It works, but obviously its messy and n00by. Any suggestions on how I can
write this code better?


----
def anti_vowel(text):
vowel = ['a', 'e', 'i', 'o', 'u']
VOWEL = ['A', 'E', 'I', 'O', 'U']
manip = []

for i in text:
manip.append(i)
fufu = 0
#
while fufu < 16:
for x in vowel:
if x in manip:
manip.remove(x)

for y in VOWEL:
if y in manip:
manip.remove(y)

fufu = fufu + 2

strong = ''.join(manip)
return strong

----

Thanks - Vusa
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Zachary Ware
2015-10-28 16:09:24 UTC
Permalink
Post by Vusa Moyo
Hi Guys,
I've written a script to remove vowels from a string/sentence.
the while loop I'm using below is to take care of duplicate vowels found in
a sentence, ie
anti_vowel('The cow moos louder than the frog')
It works, but obviously its messy and n00by. Any suggestions on how I can
write this code better?
First off, the code that works (by "works" I mean "passes its tests")
is far better than the code that doesn't, no matter what form that
code takes. That said, there are several tricks you can use to
significantly shorten your function here.
I'd rather name this "remove_vowels", since that's what it *does*
rather than what it *is* is an English sense.
Post by Vusa Moyo
vowel = ['a', 'e', 'i', 'o', 'u']
VOWEL = ['A', 'E', 'I', 'O', 'U']
Strings can be thought of as tuples optimized for characters, with
some special methods. Tuples, in turn, can be thought of as immutable
lists. So the above can be shortened to:

vowel = 'aeiou'
VOWEL = 'AEIOU'

Using one of those special methods I mentioned:

vowel = 'aeiou'
VOWEL = vowel.upper()

But do we really need two separate vowel containers?

vowels = 'aeiou'
all_vowels = vowels + vowels.upper()

Or to save a name, and some typing:

vowels = 'aeiou'
vowels += vowels.upper()
Post by Vusa Moyo
manip = []
manip.append(i)
Any time you have the pattern "create an empty list, then append to it
in a for loop", think "comprehension". The above could be shortened
to:

manip = [i for i in text]

Or, since the list constructor takes an iterable argument and strings
give characters upon iteration:

manip = list(text)

But we don't really need manip at all, as I'll show further down.
Post by Vusa Moyo
fufu = 0
#
This is a fairly weird way to spell "loop 8 times", if I'm honest :).
A more idiomatic approach would be to get rid of 'fufu' and do this
instead:

for each in range(8):

Which loops 8 times and assigns the number of the loop (0-7) to the
name 'each' each time around. 'each' could be any valid identifier
('_' is commonly used for this), 'each' just makes sense reading the
line as English.
Post by Vusa Moyo
manip.remove(x)
manip.remove(y)
Above, we combined 'vowel' and 'VOWEL' into 'vowels', so these can be
shortened into a single loop by removing the second loop and changing
the first to iterate over 'vowels' instead of 'vowel'. But instead of
removing values from a list we just built, it's easier to build the
list without those values in the first place, see below.
Post by Vusa Moyo
fufu = fufu + 2
This line goes away with the change from 'while' to 'for each in range'.
Post by Vusa Moyo
strong = ''.join(manip)
return strong
I suspect this was meant to be 'string' :). Anyway, 'return' can
return any expression not just a name, so this could be just:

return ''.join(manip)

So, what was I talking about with not needing 'manip' and building the
list without the values in the first place? Combining some other
stuff mentioned above, we can build a list of the characters of the
given text, minus vowels, using a comprehension:

list_of_chars_without_vowels = [c for c in text if c not in vowels]

To better understand what's going on here, you can "unroll" the
comprehension by initializing the name to an empty list, then moving
the initial expression (the "c" in "c for ...") to an append call all
the way inside:

list_of_chars_without_vowels = []
for c in text:
if c not in vowels:
list_of_chars_without_vowels.append(c)

'list_of_chars_without_vowels' is then in the same state your 'manip'
was in after the loops, so the loops go away entirely.
'list_of_chars_without_vowels' is an unwieldy name, but we don't
actually need to name it:

return ''.join([c for c in text if c not in vowels])

And one final optimization (which in this case is more of a finger
optimization than a performance optimization), we can drop the square
brackets to turn the list comprehension into a generator expression:

return ''.join(c for c in text if c not in vowels)

The difference between the two above statements is that the first
calculates the entire list of characters, then passes it to ''.join(),
which iterates through the list to create the final string, while the
second creates a generator and passes it to ''.join(), and the
generator calculates and yields the next character each time ''.join()
calls next() on it.

To put everything together, here's my final version, with a docstring,
a punny Easter egg, and a very simplistic test that is not adequate
testing:

import random

def remove_vowels(text):
"""Remove all vowels from 'text' and return the result."""
vowels = 'aeiou' + random.choice(['y', '']) # "and sometimes y"
vowels += vowels.upper()
return ''.join(c for c in text if c not in vowels

assert remove_vowels('Did It work? Looks like.') == 'Dd t wrk? Lks Lke.'

Hoping I may have taught you something,
--
Zach
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Zachary Ware
2015-10-28 16:11:18 UTC
Permalink
On Wed, Oct 28, 2015 at 11:09 AM, Zachary Ware
Post by Zachary Ware
assert remove_vowels('Did It work? Looks like.') == 'Dd t wrk? Lks Lke.'
Of course I typo'd here (that's what you get for not testing!): there
should be no final 'e' and the last 'L' should be lower-case.

assert remove_vowels('Did It work? Looks like.') == 'Dd t wrk? Lks lk.'
--
Zach
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Zachary Ware
2015-10-28 19:06:00 UTC
Permalink
On Wed, Oct 28, 2015 at 11:09 AM, Zachary Ware
Post by Zachary Ware
return ''.join(c for c in text if c not in vowels
Looking again, I see I typo'd here too. There should of course be a
')' at the end.
--
Zach
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Peter Otten
2015-10-28 16:37:09 UTC
Permalink
Post by Vusa Moyo
I've written a script to remove vowels from a string/sentence.
the while loop I'm using below is to take care of duplicate vowels found
in a sentence, ie
anti_vowel('The cow moos louder than the frog')
It works, but obviously its messy and n00by. Any suggestions on how I can
write this code better?
(I'm assuming Python3)
Post by Vusa Moyo
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alex Kleider
2015-10-28 17:07:50 UTC
Permalink
Post by Peter Otten
Post by Vusa Moyo
I've written a script to remove vowels from a string/sentence.
the while loop I'm using below is to take care of duplicate vowels found
in a sentence, ie
anti_vowel('The cow moos louder than the frog')
It works, but obviously its messy and n00by. Any suggestions on how I can
write this code better?
(I'm assuming Python3)
Post by Vusa Moyo
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'
I didn't know about the possibility of a third argument. Thanks, Peter.

from the docs:
"""
static str.maketrans(x[, y[, z]])

This static method returns a translation table usable for
str.translate().

If there is only one argument, it must be a dictionary mapping
Unicode ordinals (integers) or characters (strings of length 1) to
Unicode ordinals, strings (of arbitrary lengths) or None. Character keys
will then be converted to ordinals.

If there are two arguments, they must be strings of equal length,
and in the resulting dictionary, each character in x will be mapped to
the character at the same position in y. If there is a third argument,
it must be a string, whose characters will be mapped to None in the
result.
"""

Although not explicitly stated, I assume that if there is a third
argument, the first 2 will be ignored.
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Peter Otten
2015-10-28 17:28:06 UTC
Permalink
Post by Alex Kleider
Post by Peter Otten
Post by Vusa Moyo
I've written a script to remove vowels from a string/sentence.
the while loop I'm using below is to take care of duplicate vowels found
in a sentence, ie
anti_vowel('The cow moos louder than the frog')
It works, but obviously its messy and n00by. Any suggestions on how I can
write this code better?
(I'm assuming Python3)
Post by Vusa Moyo
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'
I didn't know about the possibility of a third argument. Thanks, Peter.
"""
static str.maketrans(x[, y[, z]])
This static method returns a translation table usable for
str.translate().
If there is only one argument, it must be a dictionary mapping
Unicode ordinals (integers) or characters (strings of length 1) to
Unicode ordinals, strings (of arbitrary lengths) or None. Character keys
will then be converted to ordinals.
If there are two arguments, they must be strings of equal length,
and in the resulting dictionary, each character in x will be mapped to
the character at the same position in y. If there is a third argument,
it must be a string, whose characters will be mapped to None in the
result.
"""
Although not explicitly stated, I assume that if there is a third
argument, the first 2 will be ignored.
Don't guess, fire up the interactive interpreter ;)
Post by Alex Kleider
Post by Peter Otten
Post by Vusa Moyo
"abcdef".translate(str.maketrans("acf", "ACF", "bde"))
'ACF'

All argument have an effect. Now have a look at the dict created by
Post by Alex Kleider
Post by Peter Otten
Post by Vusa Moyo
str.maketrans("acf", "ACF", "bde")
{97: 65, 98: None, 99: 67, 100: None, 101: None, 102: 70}

If the value is an int, str.translate() replaces chr(key) with chr(value),
if the value is None chr(key) is removed.

You can also replace one char with multiple chars, but for that you have to
Post by Alex Kleider
Post by Peter Otten
Post by Vusa Moyo
"ähnlich üblich löblich".translate(
... {ord(a): b for a, b in [
... ("ä", "ae"), ("ö", "oe"), ("ü", "ue")]})
'aehnlich ueblich loeblich'


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinf
Alan Gauld
2015-10-28 17:25:36 UTC
Permalink
Post by Peter Otten
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'
Even easier, forget the maketrans stuff and just use

'The cow moos louder than the frog'.translate(None,'aeiouAEIOU')
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Peter Otten
2015-10-28 17:35:20 UTC
Permalink
Post by Alan Gauld
Post by Peter Otten
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'
Even easier, forget the maketrans stuff and just use
'The cow moos louder than the frog'.translate(None,'aeiouAEIOU')
This only works for byte strings, not unicode.

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-10-28 18:06:10 UTC
Permalink
Post by Peter Otten
Post by Alan Gauld
Post by Peter Otten
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'
Even easier, forget the maketrans stuff and just use
'The cow moos louder than the frog'.translate(None,'aeiouAEIOU')
This only works for byte strings, not unicode.
Aha, I tried it in Python 2.7 which worked, but I didn't
think about v3...
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Mark Lawrence
2015-10-29 07:50:32 UTC
Permalink
Post by Alan Gauld
Post by Peter Otten
Post by Alan Gauld
Post by Peter Otten
'The cow moos louder than the frog'.translate(str.maketrans("", "",
"aeiouAEIOU"))
'Th cw ms ldr thn th frg'
Even easier, forget the maketrans stuff and just use
'The cow moos louder than the frog'.translate(None,'aeiouAEIOU')
This only works for byte strings, not unicode.
Aha, I tried it in Python 2.7 which worked, but I didn't
think about v3...
Seems like as good a place as any to point out that in Python 3 all of
the following also exist.

static bytes.maketrans(from, to)
bytes.translate(table[, delete])

static bytearray.maketrans(from, to)
bytearray.translate(table[, delete])
--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alex Kleider
2015-10-28 16:54:46 UTC
Permalink
Post by Vusa Moyo
Hi Guys,
I've written a script to remove vowels from a string/sentence.
the while loop I'm using below is to take care of duplicate vowels found in
a sentence, ie
anti_vowel('The cow moos louder than the frog')
It works, but obviously its messy and n00by. Any suggestions on how I can
write this code better?
----
vowel = ['a', 'e', 'i', 'o', 'u']
VOWEL = ['A', 'E', 'I', 'O', 'U']
manip = []
manip.append(i)
fufu = 0
#
manip.remove(x)
manip.remove(y)
fufu = fufu + 2
strong = ''.join(manip)
return strong
----
Thanks - Vusa
This struck me as a good place to utilize list comprehension.


VOWELS = 'aeiouAEIOU'

def remove_chars(s, chars2remove=VOWELS):
"""Returns the string s but without any of
the characters found in chars2remove.
If given only one parameter, defaults to removing vowels.
"""
s_as_list = [char for char in s]
without_chars2remove = [
char for char in s_as_list if char not in chars2remove]
# print(s_as_list) # for testing
# print(without_chars2remove) # ditto
return "".join(without_chars2remove)

if __name__ == "__main__":
print(remove_chars(
'The cow moos louder than the frog'))



There may be some other constructs (the string join method on the empty
string)
to which you haven't yet been exposed.
Confession: I'm submitting it probably as much to garner comments from
the
pundits as to help you.
cheers,
Alex
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Vusa Moyo
2015-10-29 07:12:55 UTC
Permalink
Thanks Meenu.

str.translate.

Worked like a charm for python 3.5.

And thanks Alan Gauld for the 2.7 version.

Appreciate the help guys. You guys are awesome.

Regards

Vusa
Hi Vusa,
I was not able to reply through mail list due to some issue. So just
replying through email.
We can make use of string translate method for more pythonic way. If you
***************************************************************************
import string
word = str.translate(None, 'aeiouAEIOU')
return word
print anti_vowel('The cow moos louder than the frog')
***************************************************************************
And if you are using python 3.x, "None" inside the str.translate method
***************************************************************************
import string
word = str.translate(str.maketrans("","","aeiouAEIOU"))
return(word)
print(anti_vowel("The cow moos louder than the frog"))
***************************************************************************
The above code should work with python 2.x as well with python 2 syntax as
import string
word = str.translate(string.maketrans('', ''), 'aeiouAEIOU')
return word
print anti_vowel('The cow moos louder than the frog')
If you want to know more about translate method, please follow the link,
https://docs.python.org/2/library/string.html#string-functions
I hope you will get much more options through mailing list.
Happy python:)
Thanks,
Meenakshi
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Loading...