For the moment, let's ignore is_vowel
itself, and just look at the higher level: what we're doing is copying data from some source to some destination, while removing any items that meet some specified criteria.
As it happens, the standard library already has an algorithm to do exactly that: std::remove_copy_if
(I know: crappy name; not clear what it really does--but that really is what it does).
So, I will posit that at the top level, this is how we should be carrying out the overall task:
remove_copy_if(some_input, some_output, your_criteria);
In the case of files, we can use istream_iterator
s for the input and an ostream_iterator
for the output, making this something like:
std::ifstream file{"data.txt"};
std::ofstream outfile{"new.txt"};
file >> std::noskipws;
std::istream_iterator<char> in{file}, end;
std::ostream_iterator<char> out{outfile};
std::remove_copy_if(in, end, out, is_vowel);
Looking at is_vowel
itself: it can be defined a number of different ways, depending on the degree to which you care about speed vs. space usage. If you care primarily about space, storing the vowels in a string and searching that string (e.g., as suggested by @utnapistim) is a perfectly fine method. Under the circumstances (copying from one file to another) the I/O will almost certainly be (quite a lot) slower than the processing, so this is probably the most sensible approach.
For another possibility, however, let's assume our source and destination were just strings in memory instead, so we wanted to optimize for speed instead. In this case, we might consider a somewhat different approach. One possibility would be an array (or vector) of Booleans, one for each possible char
value, specifying whether that character is a vowel. We probably want to wrap this up in a neat little class so we don't need to deal with the details.
class is_vowel {
bool table[std::numeric_limits<unsigned char>::max()];
static const char vowels = "aeiouAEIOU";
public:
// Here we set up our table. We start by initializing everything to `false`
// then we set the entries that really do represent vowels to true.
is_vowel() : table(false) {
for (auto ch : vowels)
table[ch] = true;
}
bool operator()(unsigned char ch) { return table[ch]; }
};
Unfortunately, it's not always easy to decide which sort of approach will be the best for a given circumstance, but such is life sometimes.
There are also a few intermediate points that probably don't make sense for this specific case, but can for similar cases. For example, here we're dealing with such a small number of items (around 10) that searching the string isn't particularly slow. If we had a list of, say, a few hundred items we wanted to remove, searching the whole list every time could get pretty slow--for such cases, we might consider sorting the list of items to remove, and using a binary search.
I'm starting to get into pretty hypothetical areas though, so perhaps I should just stop for now... :-)