Reputation: 1479
For example to traverse a string and count the number of vowels I could use
for (int i=0; (x=inputString[i])!='\0';i++)
if (x=='a' || x=='e' || x=='i' || x=='o' || x=='u') numVowels++;
In functional languages like haskell or erlang we can do lists:member(x,"aeiou")
In some object oriented languages I can do something like ["a","e","i","o","u"].find(x)
What's the cleanest way to do this in C++ without the x==.. || x==.. || ...
Upvotes: 2
Views: 341
Reputation: 279255
The title ("most efficient") doesn't seem to match the question ("cleanest").
Given that ["a","e","i","o","u"].find(x)
counts as "clean", I suppose that the closest C++ equivalent is std::string("aeiou").find(x) != -1
.
I'd also clean up the loop. If you insist on a nul-terminated string for the input, then:
static const std::string lower_vowels("aeiou");
char x;
while ((x = *inputString++)) {
numVowels += (lower_vowels.find(x) != -1);
}
If you change the input to std::string
then:
for (char x : inputString) {
numVowels += (lower_vowels.find(x) != -1);
}
It's probably not the most efficient, but that's another story. What you have is likely to be pretty close to optimal. I doubt you'll beat it without some fairly ugly code, because what you're basically saying is "can I do better than the compiler at optimizing these 5 comparisons against integral constants?"
Upvotes: 1
Reputation: 9278
Or
for (auto c: inputString)
{
c = std::tolower(c);
if ((c == 'a') || ... (c == 'u'))
{
++numVowels;
}
}
Just because a language lets you write it in one line doesn't mean it's faster.
If you really, really wanted to get rid of the ==
you could do
#include <stdint.h>
// a b c d e ....
const uint8_t TABLE[] = { 1, 0, 0, 0, 1, ... };
for (uint8_t c : inputString)
{
if (std::isalpha(c))
{
numVowels += TABLE[std::tolower(c) - 'a'];
}
}
Upvotes: 3
Reputation: 153840
In C++ you could use std::find()()
:
std::count_if(str.begin(), str.end(), [](char c) {
static std::string const vowels("aeiou");
return vowels.end() != std::find(vowels.begin(), vowels.end(), c);
});
Sadly, the notation for algorithms doesn't support ranges [yet]. If it did, the operation could be written somewhat nicer as
ranges::count_if(str, [](char c){ return !ranges::find("aeiou"r, c).empty(); });
where r
is a suitable user-defined literal producing an character sequence range.
Upvotes: 1
Reputation: 3379
inputString.find_first_of("aeiou");
This will give you the first index of any matching element. You can do this in loop to get all matching element:
size_t idx=0;
do{
size_t current = inputString.find_first_of("aeiou",idx);
idx = current;
}
while(current!=string::npos);
Upvotes: 3
Reputation: 1788
As far as I know, that is the "best" way to do it. To make it cleaner, you might write a macro or function that just carries out that comparison, i.e. bool CheckForVowel(char in)
or something like that. Then, you could just use that function: if(CheckForVowel(x)){...}
Upvotes: 2
Reputation: 477040
I'd use this:
#include <algorithm>
auto const numVowels = std::count_if(inputString.begin(), inputString.end(),
[](char c) { return c == 'a' || /* ... */ || c == 'u'; })
Upvotes: 2