Counting lowercase and uppercase letters in a string in Python
Clash Royale CLAN TAG#URR8PPP
$begingroup$
I am writing a program to count the number of uppercase and lowercase letters in a string. I came up with something that works, but as I am still a beginner I have a feeling writing the code this way is probably considered "clumsy."
Here is what I have:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
Output:
Give me a phrase: tHe Sun is sHininG
The number of uppercase letters in your phrase is: 4
The number of lowercase letters in your phrase is: 11
I would like to learn how to write neat, beautiful code so I am wondering if there is a more efficient and elegant way to code this.
python beginner python-3.x strings
$endgroup$
migrated from stackoverflow.com Feb 7 at 0:03
This question came from our site for professional and enthusiast programmers.
add a comment |
$begingroup$
I am writing a program to count the number of uppercase and lowercase letters in a string. I came up with something that works, but as I am still a beginner I have a feeling writing the code this way is probably considered "clumsy."
Here is what I have:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
Output:
Give me a phrase: tHe Sun is sHininG
The number of uppercase letters in your phrase is: 4
The number of lowercase letters in your phrase is: 11
I would like to learn how to write neat, beautiful code so I am wondering if there is a more efficient and elegant way to code this.
python beginner python-3.x strings
$endgroup$
migrated from stackoverflow.com Feb 7 at 0:03
This question came from our site for professional and enthusiast programmers.
$begingroup$
@juanpa.arrivillaga All critiques belong in answers, not comments.
$endgroup$
– 200_success
Feb 7 at 1:49
add a comment |
$begingroup$
I am writing a program to count the number of uppercase and lowercase letters in a string. I came up with something that works, but as I am still a beginner I have a feeling writing the code this way is probably considered "clumsy."
Here is what I have:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
Output:
Give me a phrase: tHe Sun is sHininG
The number of uppercase letters in your phrase is: 4
The number of lowercase letters in your phrase is: 11
I would like to learn how to write neat, beautiful code so I am wondering if there is a more efficient and elegant way to code this.
python beginner python-3.x strings
$endgroup$
I am writing a program to count the number of uppercase and lowercase letters in a string. I came up with something that works, but as I am still a beginner I have a feeling writing the code this way is probably considered "clumsy."
Here is what I have:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
Output:
Give me a phrase: tHe Sun is sHininG
The number of uppercase letters in your phrase is: 4
The number of lowercase letters in your phrase is: 11
I would like to learn how to write neat, beautiful code so I am wondering if there is a more efficient and elegant way to code this.
python beginner python-3.x strings
python beginner python-3.x strings
edited Feb 7 at 1:49
200_success
130k16153417
130k16153417
asked Feb 6 at 22:35
Madrid_dataladyMadrid_datalady
434
434
migrated from stackoverflow.com Feb 7 at 0:03
This question came from our site for professional and enthusiast programmers.
migrated from stackoverflow.com Feb 7 at 0:03
This question came from our site for professional and enthusiast programmers.
$begingroup$
@juanpa.arrivillaga All critiques belong in answers, not comments.
$endgroup$
– 200_success
Feb 7 at 1:49
add a comment |
$begingroup$
@juanpa.arrivillaga All critiques belong in answers, not comments.
$endgroup$
– 200_success
Feb 7 at 1:49
$begingroup$
@juanpa.arrivillaga All critiques belong in answers, not comments.
$endgroup$
– 200_success
Feb 7 at 1:49
$begingroup$
@juanpa.arrivillaga All critiques belong in answers, not comments.
$endgroup$
– 200_success
Feb 7 at 1:49
add a comment |
4 Answers
4
active
oldest
votes
$begingroup$
Your code is mostly fine. I'd suggest more meaningful names for variables, e.g. i
is typically a name for integer/index variables; since you're iterating over letters/characters, you might choose c
, char
, let
, or letter
. For stri
, you might just name it phrase
(that's what you asked for from the user after all). You get the idea. Make the names self-documenting.
Arguably you could make it look "prettier" by performing a single pass per test, replacing:
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
with:
stri_up = sum(1 for let in stri if let.isupper())
stri_lo = sum(1 for let in stri if let.islower())
That's in theory less efficient, since it has to traverse stri
twice, while your original code only does it once, but in practice it's likely faster; on the CPython reference interpreter, sum
is highly optimized for this case and avoids constructing a bunch of intermediate int
objects while summing.
$endgroup$
7
$begingroup$
You can just dosum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.
$endgroup$
– 200_success
Feb 7 at 1:48
6
$begingroup$
@200_success: True, but I'm using dirty knowledge here; thesum
fast path only fires forint
(PyLong_Object
at C layer) exactly (noint
subclasses accepted, includingbool
); yieldingbool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; usingbool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.
$endgroup$
– ShadowRanger
Feb 7 at 2:47
1
$begingroup$
Just for comparison, a microbenchmark wherestri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded1
s conditionally.
$endgroup$
– ShadowRanger
Feb 7 at 3:20
2
$begingroup$
@200_success"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.
$endgroup$
– Baldrickk
Feb 7 at 16:29
1
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu'samerican-english-insane
file repeated 10 times (len
of 68753140). Mysum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeatedamerican-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).
$endgroup$
– ShadowRanger
Feb 7 at 22:14
|
show 3 more comments
$begingroup$
Small optimisation
If you know a character is an upper, you don't have to test for lower anymore:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
elif i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
$endgroup$
1
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
add a comment |
$begingroup$
TLDR: Looks good! This is perfectly reasonable solution for your problem. It's certainly not clumsy.
Optimisations
The optimisation ShadowRanger points out, is faster, due to compiler optimisations, I wouldn't worry about this at a beginner level (and no even at an experienced level really, unless it was critical to make every optimisation.
The optimisation of checking only isupper
or islower
that some have pointed out probably isn't valid. If your input is guaranteed to be only alphabetic characters A-Z or a-z, then you can assume that if it's not upper, it's lower. But this doesn't apply generally. '1' is neither lower or upper for example. Checking only isupper
and assuming the opposite on a False
result, you would increment your 'lower' counter and that wouldn't be correct.
Your code provides a correct solution and doesn't break when the user inputs an empty string or non alphabetic characters, which is why I'd consider it good.
Possible next step:
Since you say you're a beginner, I'd look up writing tests if you haven't already and learn a little about how to write good tests. Checking empty input and special characters would be an interesting start. Some terms to search would be edge-case
$endgroup$
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
add a comment |
$begingroup$
You can approach this in a cleaner manner by using the filter function; for example:
stri = input("Give me a phrase:")
# Filter will return every character in stri x, where x.isupper() returns true
stri_up = filter(str.isupper, stri)
# Filter returns an iterator, to get the length we cast to a list first
up_count = len(list(stri_up))
stri_lo = filter(str.islower, stri)
lo_count = len(list(stri_lo))
print("The number of uppercase letters in your phrase is:", up_count)
print("The number of lowercase letters in your phrase is:", lo_count)
As a note this is a less efficient approach, since you iterate through the string twice in the filter calls, but it is a different way of approaching the problem, and hopefully get you introduced to some more advanced python techniques.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213005%2fcounting-lowercase-and-uppercase-letters-in-a-string-in-python%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Your code is mostly fine. I'd suggest more meaningful names for variables, e.g. i
is typically a name for integer/index variables; since you're iterating over letters/characters, you might choose c
, char
, let
, or letter
. For stri
, you might just name it phrase
(that's what you asked for from the user after all). You get the idea. Make the names self-documenting.
Arguably you could make it look "prettier" by performing a single pass per test, replacing:
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
with:
stri_up = sum(1 for let in stri if let.isupper())
stri_lo = sum(1 for let in stri if let.islower())
That's in theory less efficient, since it has to traverse stri
twice, while your original code only does it once, but in practice it's likely faster; on the CPython reference interpreter, sum
is highly optimized for this case and avoids constructing a bunch of intermediate int
objects while summing.
$endgroup$
7
$begingroup$
You can just dosum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.
$endgroup$
– 200_success
Feb 7 at 1:48
6
$begingroup$
@200_success: True, but I'm using dirty knowledge here; thesum
fast path only fires forint
(PyLong_Object
at C layer) exactly (noint
subclasses accepted, includingbool
); yieldingbool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; usingbool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.
$endgroup$
– ShadowRanger
Feb 7 at 2:47
1
$begingroup$
Just for comparison, a microbenchmark wherestri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded1
s conditionally.
$endgroup$
– ShadowRanger
Feb 7 at 3:20
2
$begingroup$
@200_success"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.
$endgroup$
– Baldrickk
Feb 7 at 16:29
1
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu'samerican-english-insane
file repeated 10 times (len
of 68753140). Mysum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeatedamerican-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).
$endgroup$
– ShadowRanger
Feb 7 at 22:14
|
show 3 more comments
$begingroup$
Your code is mostly fine. I'd suggest more meaningful names for variables, e.g. i
is typically a name for integer/index variables; since you're iterating over letters/characters, you might choose c
, char
, let
, or letter
. For stri
, you might just name it phrase
(that's what you asked for from the user after all). You get the idea. Make the names self-documenting.
Arguably you could make it look "prettier" by performing a single pass per test, replacing:
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
with:
stri_up = sum(1 for let in stri if let.isupper())
stri_lo = sum(1 for let in stri if let.islower())
That's in theory less efficient, since it has to traverse stri
twice, while your original code only does it once, but in practice it's likely faster; on the CPython reference interpreter, sum
is highly optimized for this case and avoids constructing a bunch of intermediate int
objects while summing.
$endgroup$
7
$begingroup$
You can just dosum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.
$endgroup$
– 200_success
Feb 7 at 1:48
6
$begingroup$
@200_success: True, but I'm using dirty knowledge here; thesum
fast path only fires forint
(PyLong_Object
at C layer) exactly (noint
subclasses accepted, includingbool
); yieldingbool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; usingbool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.
$endgroup$
– ShadowRanger
Feb 7 at 2:47
1
$begingroup$
Just for comparison, a microbenchmark wherestri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded1
s conditionally.
$endgroup$
– ShadowRanger
Feb 7 at 3:20
2
$begingroup$
@200_success"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.
$endgroup$
– Baldrickk
Feb 7 at 16:29
1
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu'samerican-english-insane
file repeated 10 times (len
of 68753140). Mysum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeatedamerican-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).
$endgroup$
– ShadowRanger
Feb 7 at 22:14
|
show 3 more comments
$begingroup$
Your code is mostly fine. I'd suggest more meaningful names for variables, e.g. i
is typically a name for integer/index variables; since you're iterating over letters/characters, you might choose c
, char
, let
, or letter
. For stri
, you might just name it phrase
(that's what you asked for from the user after all). You get the idea. Make the names self-documenting.
Arguably you could make it look "prettier" by performing a single pass per test, replacing:
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
with:
stri_up = sum(1 for let in stri if let.isupper())
stri_lo = sum(1 for let in stri if let.islower())
That's in theory less efficient, since it has to traverse stri
twice, while your original code only does it once, but in practice it's likely faster; on the CPython reference interpreter, sum
is highly optimized for this case and avoids constructing a bunch of intermediate int
objects while summing.
$endgroup$
Your code is mostly fine. I'd suggest more meaningful names for variables, e.g. i
is typically a name for integer/index variables; since you're iterating over letters/characters, you might choose c
, char
, let
, or letter
. For stri
, you might just name it phrase
(that's what you asked for from the user after all). You get the idea. Make the names self-documenting.
Arguably you could make it look "prettier" by performing a single pass per test, replacing:
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
if i.islower():
stri_lo += 1
with:
stri_up = sum(1 for let in stri if let.isupper())
stri_lo = sum(1 for let in stri if let.islower())
That's in theory less efficient, since it has to traverse stri
twice, while your original code only does it once, but in practice it's likely faster; on the CPython reference interpreter, sum
is highly optimized for this case and avoids constructing a bunch of intermediate int
objects while summing.
answered Feb 7 at 0:09
ShadowRangerShadowRanger
22623
22623
7
$begingroup$
You can just dosum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.
$endgroup$
– 200_success
Feb 7 at 1:48
6
$begingroup$
@200_success: True, but I'm using dirty knowledge here; thesum
fast path only fires forint
(PyLong_Object
at C layer) exactly (noint
subclasses accepted, includingbool
); yieldingbool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; usingbool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.
$endgroup$
– ShadowRanger
Feb 7 at 2:47
1
$begingroup$
Just for comparison, a microbenchmark wherestri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded1
s conditionally.
$endgroup$
– ShadowRanger
Feb 7 at 3:20
2
$begingroup$
@200_success"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.
$endgroup$
– Baldrickk
Feb 7 at 16:29
1
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu'samerican-english-insane
file repeated 10 times (len
of 68753140). Mysum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeatedamerican-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).
$endgroup$
– ShadowRanger
Feb 7 at 22:14
|
show 3 more comments
7
$begingroup$
You can just dosum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.
$endgroup$
– 200_success
Feb 7 at 1:48
6
$begingroup$
@200_success: True, but I'm using dirty knowledge here; thesum
fast path only fires forint
(PyLong_Object
at C layer) exactly (noint
subclasses accepted, includingbool
); yieldingbool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; usingbool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.
$endgroup$
– ShadowRanger
Feb 7 at 2:47
1
$begingroup$
Just for comparison, a microbenchmark wherestri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded1
s conditionally.
$endgroup$
– ShadowRanger
Feb 7 at 3:20
2
$begingroup$
@200_success"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.
$endgroup$
– Baldrickk
Feb 7 at 16:29
1
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu'samerican-english-insane
file repeated 10 times (len
of 68753140). Mysum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeatedamerican-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).
$endgroup$
– ShadowRanger
Feb 7 at 22:14
7
7
$begingroup$
You can just do
sum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.$endgroup$
– 200_success
Feb 7 at 1:48
$begingroup$
You can just do
sum(c.isupper() for c in phrase)
, because boolean will be treated as 0 or 1 when summing.$endgroup$
– 200_success
Feb 7 at 1:48
6
6
$begingroup$
@200_success: True, but I'm using dirty knowledge here; the
sum
fast path only fires for int
(PyLong_Object
at C layer) exactly (no int
subclasses accepted, including bool
); yielding bool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; using bool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.$endgroup$
– ShadowRanger
Feb 7 at 2:47
$begingroup$
@200_success: True, but I'm using dirty knowledge here; the
sum
fast path only fires for int
(PyLong_Object
at C layer) exactly (no int
subclasses accepted, including bool
); yielding bool
blocks that optimization (and involves a lot more yields from the genexpr that can be avoided). Plus, I consider it more obvious to actually sum integers conditionally; using bool
for numeric value is perfectly legal, just a little more magical than necessary, given the minimal benefit.$endgroup$
– ShadowRanger
Feb 7 at 2:47
1
1
$begingroup$
Just for comparison, a microbenchmark where
stri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded 1
s conditionally.$endgroup$
– ShadowRanger
Feb 7 at 3:20
$begingroup$
Just for comparison, a microbenchmark where
stri
/phrase
is just one of each ASCII character (''.join(map(chr, range(128)))
), takes 15.3 µs to complete on my computer using your code, vs. 10.5 µs for summing hardcoded 1
s conditionally.$endgroup$
– ShadowRanger
Feb 7 at 3:20
2
2
$begingroup$
@200_success
"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.$endgroup$
– Baldrickk
Feb 7 at 16:29
$begingroup$
@200_success
"But", I thought, "wouldn't a lot of punctiation (e.g. ./@#~";:' etc.) cause that single line to be incorrect?"
= 2 uppers and 109 lowers when it should be 70 lowers.$endgroup$
– Baldrickk
Feb 7 at 16:29
1
1
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu's
american-english-insane
file repeated 10 times (len
of 68753140). My sum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeated american-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).$endgroup$
– ShadowRanger
Feb 7 at 22:14
$begingroup$
@Baldrickk: I modified the microbenchmark to run against the contents of Ubuntu's
american-english-insane
file repeated 10 times (len
of 68753140). My sum
was fastest by a small amount (for 10x case, 8.34 s), the OP's code close behind (8.48 s), and the 200_success's rather further behind (11 s). The same pattern held for unrepeated american-english-insane
, with the same margins. I suspect the cache doesn't matter; any system worth its salt can recognize sequential memory access and populate the cache ahead of time (Python is slow enough to give it time to do so).$endgroup$
– ShadowRanger
Feb 7 at 22:14
|
show 3 more comments
$begingroup$
Small optimisation
If you know a character is an upper, you don't have to test for lower anymore:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
elif i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
$endgroup$
1
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
add a comment |
$begingroup$
Small optimisation
If you know a character is an upper, you don't have to test for lower anymore:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
elif i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
$endgroup$
1
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
add a comment |
$begingroup$
Small optimisation
If you know a character is an upper, you don't have to test for lower anymore:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
elif i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
$endgroup$
Small optimisation
If you know a character is an upper, you don't have to test for lower anymore:
stri = input("Give me a phrase:")
stri_up = 0
stri_lo = 0
for i in stri:
if i.isupper():
stri_up += 1
elif i.islower():
stri_lo += 1
print("The number of uppercase letters in your phrase is:", stri_up)
print("The number of lowercase letters in your phrase is:", stri_lo)
answered Feb 7 at 9:35
JADJAD
7071420
7071420
1
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
add a comment |
1
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
1
1
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
$begingroup$
what about punctuation?
$endgroup$
– Baldrickk
Feb 8 at 9:25
add a comment |
$begingroup$
TLDR: Looks good! This is perfectly reasonable solution for your problem. It's certainly not clumsy.
Optimisations
The optimisation ShadowRanger points out, is faster, due to compiler optimisations, I wouldn't worry about this at a beginner level (and no even at an experienced level really, unless it was critical to make every optimisation.
The optimisation of checking only isupper
or islower
that some have pointed out probably isn't valid. If your input is guaranteed to be only alphabetic characters A-Z or a-z, then you can assume that if it's not upper, it's lower. But this doesn't apply generally. '1' is neither lower or upper for example. Checking only isupper
and assuming the opposite on a False
result, you would increment your 'lower' counter and that wouldn't be correct.
Your code provides a correct solution and doesn't break when the user inputs an empty string or non alphabetic characters, which is why I'd consider it good.
Possible next step:
Since you say you're a beginner, I'd look up writing tests if you haven't already and learn a little about how to write good tests. Checking empty input and special characters would be an interesting start. Some terms to search would be edge-case
$endgroup$
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
add a comment |
$begingroup$
TLDR: Looks good! This is perfectly reasonable solution for your problem. It's certainly not clumsy.
Optimisations
The optimisation ShadowRanger points out, is faster, due to compiler optimisations, I wouldn't worry about this at a beginner level (and no even at an experienced level really, unless it was critical to make every optimisation.
The optimisation of checking only isupper
or islower
that some have pointed out probably isn't valid. If your input is guaranteed to be only alphabetic characters A-Z or a-z, then you can assume that if it's not upper, it's lower. But this doesn't apply generally. '1' is neither lower or upper for example. Checking only isupper
and assuming the opposite on a False
result, you would increment your 'lower' counter and that wouldn't be correct.
Your code provides a correct solution and doesn't break when the user inputs an empty string or non alphabetic characters, which is why I'd consider it good.
Possible next step:
Since you say you're a beginner, I'd look up writing tests if you haven't already and learn a little about how to write good tests. Checking empty input and special characters would be an interesting start. Some terms to search would be edge-case
$endgroup$
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
add a comment |
$begingroup$
TLDR: Looks good! This is perfectly reasonable solution for your problem. It's certainly not clumsy.
Optimisations
The optimisation ShadowRanger points out, is faster, due to compiler optimisations, I wouldn't worry about this at a beginner level (and no even at an experienced level really, unless it was critical to make every optimisation.
The optimisation of checking only isupper
or islower
that some have pointed out probably isn't valid. If your input is guaranteed to be only alphabetic characters A-Z or a-z, then you can assume that if it's not upper, it's lower. But this doesn't apply generally. '1' is neither lower or upper for example. Checking only isupper
and assuming the opposite on a False
result, you would increment your 'lower' counter and that wouldn't be correct.
Your code provides a correct solution and doesn't break when the user inputs an empty string or non alphabetic characters, which is why I'd consider it good.
Possible next step:
Since you say you're a beginner, I'd look up writing tests if you haven't already and learn a little about how to write good tests. Checking empty input and special characters would be an interesting start. Some terms to search would be edge-case
$endgroup$
TLDR: Looks good! This is perfectly reasonable solution for your problem. It's certainly not clumsy.
Optimisations
The optimisation ShadowRanger points out, is faster, due to compiler optimisations, I wouldn't worry about this at a beginner level (and no even at an experienced level really, unless it was critical to make every optimisation.
The optimisation of checking only isupper
or islower
that some have pointed out probably isn't valid. If your input is guaranteed to be only alphabetic characters A-Z or a-z, then you can assume that if it's not upper, it's lower. But this doesn't apply generally. '1' is neither lower or upper for example. Checking only isupper
and assuming the opposite on a False
result, you would increment your 'lower' counter and that wouldn't be correct.
Your code provides a correct solution and doesn't break when the user inputs an empty string or non alphabetic characters, which is why I'd consider it good.
Possible next step:
Since you say you're a beginner, I'd look up writing tests if you haven't already and learn a little about how to write good tests. Checking empty input and special characters would be an interesting start. Some terms to search would be edge-case
answered Feb 7 at 9:59
MattMatt
311
311
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
add a comment |
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
$begingroup$
Thank you, your comment warmed my heart and has very useful suggestions. :)
$endgroup$
– Madrid_datalady
Feb 7 at 11:11
add a comment |
$begingroup$
You can approach this in a cleaner manner by using the filter function; for example:
stri = input("Give me a phrase:")
# Filter will return every character in stri x, where x.isupper() returns true
stri_up = filter(str.isupper, stri)
# Filter returns an iterator, to get the length we cast to a list first
up_count = len(list(stri_up))
stri_lo = filter(str.islower, stri)
lo_count = len(list(stri_lo))
print("The number of uppercase letters in your phrase is:", up_count)
print("The number of lowercase letters in your phrase is:", lo_count)
As a note this is a less efficient approach, since you iterate through the string twice in the filter calls, but it is a different way of approaching the problem, and hopefully get you introduced to some more advanced python techniques.
$endgroup$
add a comment |
$begingroup$
You can approach this in a cleaner manner by using the filter function; for example:
stri = input("Give me a phrase:")
# Filter will return every character in stri x, where x.isupper() returns true
stri_up = filter(str.isupper, stri)
# Filter returns an iterator, to get the length we cast to a list first
up_count = len(list(stri_up))
stri_lo = filter(str.islower, stri)
lo_count = len(list(stri_lo))
print("The number of uppercase letters in your phrase is:", up_count)
print("The number of lowercase letters in your phrase is:", lo_count)
As a note this is a less efficient approach, since you iterate through the string twice in the filter calls, but it is a different way of approaching the problem, and hopefully get you introduced to some more advanced python techniques.
$endgroup$
add a comment |
$begingroup$
You can approach this in a cleaner manner by using the filter function; for example:
stri = input("Give me a phrase:")
# Filter will return every character in stri x, where x.isupper() returns true
stri_up = filter(str.isupper, stri)
# Filter returns an iterator, to get the length we cast to a list first
up_count = len(list(stri_up))
stri_lo = filter(str.islower, stri)
lo_count = len(list(stri_lo))
print("The number of uppercase letters in your phrase is:", up_count)
print("The number of lowercase letters in your phrase is:", lo_count)
As a note this is a less efficient approach, since you iterate through the string twice in the filter calls, but it is a different way of approaching the problem, and hopefully get you introduced to some more advanced python techniques.
$endgroup$
You can approach this in a cleaner manner by using the filter function; for example:
stri = input("Give me a phrase:")
# Filter will return every character in stri x, where x.isupper() returns true
stri_up = filter(str.isupper, stri)
# Filter returns an iterator, to get the length we cast to a list first
up_count = len(list(stri_up))
stri_lo = filter(str.islower, stri)
lo_count = len(list(stri_lo))
print("The number of uppercase letters in your phrase is:", up_count)
print("The number of lowercase letters in your phrase is:", lo_count)
As a note this is a less efficient approach, since you iterate through the string twice in the filter calls, but it is a different way of approaching the problem, and hopefully get you introduced to some more advanced python techniques.
edited Feb 7 at 17:27
answered Feb 7 at 17:14
user192377user192377
212
212
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213005%2fcounting-lowercase-and-uppercase-letters-in-a-string-in-python%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
@juanpa.arrivillaga All critiques belong in answers, not comments.
$endgroup$
– 200_success
Feb 7 at 1:49