0

I have created a set of algorithms that takes an input of a string vector, checks whether any of the strings occur more than once: if so erases all additional occurrences of the string from the vector, then outputs the new, 'lighter' array without the redundancies.

It works great except now I am to make it case-insensitive; I am attempting to simply add the toupper() std function to the == comparison statement, however it does not seem to work.

I have a more familiar background with Java and am trying to learn C++.
Can someone please show me how to correct my syntax?

// Output old list.
cout << endl << "==========\nOld list:\n==========";
for (int i = 0; i < count; i++) {
    cout << endl << list[i];
}
cout << endl << endl;

// Check uniqueness.
for (int i = 0; i < count; i++)
    for (int j = i+1; j < count; j++) {
        if (toupper(list[i]) == toupper(list[j])) {
            list[j] = "";
            count--;
        }
    }

// Output new list.
cout << endl << "==========\nNew list:\n==========";
for (int i = 0; i < count; i++) {
    cout << endl << list[i];
}
cout << endl << endl;
Jim22150
  • 511
  • 2
  • 8
  • 22

5 Answers5

1

I just did a quick google of toupper and I didn't find any string versions of it. The only standard touppper() I have seen is int toupper(int c); - that means you can only use it to compare individual characters! Have you tried stricmp()?

        if ( 0 == _stricmp(list[i], list[j]) ) {
            list[j] = "";
            count--;
        }

Depending on your compiler you may or may not have this function at your disposal.

DaveS
  • 895
  • 1
  • 8
  • 20
  • I am using VS'13 so this function would be ideal, however it seems to only be used for individual characters, not entire strings. So I could use it but I'd have to make another `for` loop, inside of the conditional, correct? – Jim22150 Mar 28 '14 at 20:35
  • @Jim22150, `stricmp()` will accept two strings as parameters so no need for another loop. If you want to continue using `toupper()` then you need a loop to compare individual chars. – DaveS Mar 28 '14 at 20:47
1

@DaveS, thanks Dave I will try that; it looks clean and short. However, I found dirtier solution using transform and making a duplicate of the old vector.

    // Output old list.
    cout << endl << "==========\nOld list:\n==========";
    for (int i = 0; i < count; i++) {
        cout << endl << list[i];
    }
    cout << endl << endl;

    // Check uniqueness.
    for (int i = 0; i < count; i++)
        for (int j = i + 1; j < count; j++) {
            std::transform(list[i].begin(), list[i].end(), list[i].begin(), ::toupper);
            std::transform(list[j].begin(), list[j].end(), list[j].begin(), ::toupper);
            if (list[i] == list[j]) {
                newlist[j] = "";
                count--;
            }
        }

    // Output new list.
    cout << endl << "==========\nNew list:\n==========";
    for (int i = 0; i < count; i++) {
        cout << endl << newlist[i];
    }
    cout << endl << endl;
Jim22150
  • 511
  • 2
  • 8
  • 22
1

Your loop leaves "holes" in the list array vector, but the size of the array vector does not change (but you decrease your upper bound count)

There are probably many other alternatives, but if you don't want to modify it much, probably you need in an addtional loop to copy non-empty elements from the list array into a new array

Edit: integrating some of the answers

First we're going to have a function to do the toUpper (this is modified from @Jim22150)

std::string stringToUpper(const std::string &input) {
    std::string toBeModified=input;
    std::transform(toBeModified.begin(), toBeModified.end(), toBeModified.begin(), ::toupper);
    return toBeModified;
}

Now, we must not leave holes, so we should use erase (as @Scott Christopher Stauffe indicated):

// Output old list.
cout << endl << "==========\nOld list:\n==========";
for (int i = 0; i < count; i++) {
    cout << endl << list[i];
}
cout << endl << endl;

// Check uniqueness.
for (int i = 0; i < count; i++)
    for (int j = i + 1; j < count; j++) {
        if(stringToUpper(list[i]) == stringToUpper(list[j])) {
            list.erase(j,1);
            count--;
        }
    }
}

// Output new list.
cout << endl << "==========\nNew list:\n==========";
for (int i = 0; i < count; i++) {
    cout << endl << newlist[i];
}
cout << endl << endl;
jsantander
  • 4,972
  • 16
  • 27
  • Yes, it would be nice to avoid this. I am trying to implement Scott's suggestion but it looks like I may need another for loop which I'd like to avoid if possible. – Jim22150 Mar 28 '14 at 20:30
  • @Jim22150 ... yes but real the problem is that you cannot shrink an array, unless you copy it. If you can use a vector instead on an array, that would allow you to erase from it... – jsantander Mar 28 '14 at 20:34
  • list[] **is** a vector, not an array. – Jim22150 Mar 28 '14 at 20:37
  • @Jim22150 ok... this was very confusing. I've edited my answer above to integrate some of the ideas floating around. I really haven't tried it. – jsantander Mar 29 '14 at 10:15
1

If you want to handle C++ strings as easily as Java strings, then the Boost String Algorithms Library is the way to go. Installing Boost may be a bit hard for a newbie C++ programmer (although it's a breeze compared to many other C++ libraries), but it pays off.

Your problem will essentially be reduced to this:

boost::algorithm::to_upper_copy(list[i]) == boost::algorithm::to_upper_copy(list[j])
Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
0

First of all,

list[j] = ""; // should never work. 

You can remove a char by using erase.

list.erase(j, 1);

Alternatively, to avoid this altogether, you could use a temporary "builder" string and just push_back chars to it when needed.

scottyeatscode
  • 606
  • 3
  • 11