简体   繁体   中英

How to use find_first_not_of with a vector of string?

Let's say I have the following object:

vector<string> data = {"12","12","12","12","13","14","15", "15", "15", "15", "18"};

I'm trying to find the first non-repeating entry in the data object. For example, data.find_first_not_of(data.at(0)); this would work if data is of string type only (no container).

How can I achieve the same thing with an object of type vector.

I looked at adjacent_find and find_if_not from the algorithm library, but to no avail.

Your suggestions are much appreciated.

What problem did you have with adjacent_find ? You should be able to use that with an inverse predicate:

std::vector<std::string> data = {"12","12","12","12","13","14","15", "15", "15", "15", "18"};

// Sort data here if necessary

auto itr = std::adjacent_find(data.cbegin(), data.cend(), std::not_equal_to<std::string>{});
if (itr != data.cend()) {
    std::cout << "First mismatch: " << *itr << " " << *std::next(itr) << std::endl;
} else {
    std::cout << "All elements equal" << std::endl;
} 

Wandbox

Since you have to go through the list at least once, and you don't know when or where you will encounter the duplicate of a number (if there is one), one way to solve this is to first gather "statistics" and then from what you've gathered you can determine the first non-duplicate.

Here is an example using std::unordered_map :

#include <algorithm>
#include <unordered_map>
#include <iostream>
#include <vector>
#include <string>

// struct to hold some information on the numbers
struct info
{
    std::string number;
    int count;
    int position;
    info(const std::string n, int c, int p) : number(n), count(c), position(p) {}
};

int main()
{

    std::vector<std::string> data = {"12","12","12","12","13","14","15", "15", "15", "15", "18"};
    std::unordered_map<std::string, info> infoMap;
    std::vector<info> vInfo;
    int pos = 0;

    // loop for each data element
    std::for_each(data.begin(), data.end(), [&](const std::string& n) 
    { 
        // insert entry into the map
        auto pr = infoMap.insert(std::make_pair(n, info(n, 0, pos)));    

        // bump up the count for this entry.
        ++pr.first->second.count;

        // bump up the postion number
        ++pos;

    });

    // create a vector of the information with a count of 1 item.
    std::for_each(infoMap.begin(), infoMap.end(), [&](std::unordered_map<std::string, info>::value_type& vt) { if (vt.second.count == 1) vInfo.push_back(vt.second); });

    // sort this by position
    std::sort(vInfo.begin(), vInfo.end(), [&](const info& pr1, const info &pr2){return pr1.position < pr2.position; });

   // output the results
    if ( vInfo.empty() )
        std::cout << "All values are duplicated\n";
    else  
        std::cout << "The first number that isn't repeated is " << vInfo.front().number << "\n";
    }

Live Example

First, we just simply go through all the entries in the vector and just tally up the count for each item. In addition, we store the position in the original list of where the item was found.

After that we filter out the ones with a count of exactly 1 and copy them to a vector. We then sort this vector based on the position they were found in the original list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM