Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Sunday, December 20, 2015

Find all elements with the same value in a vector, then erase all of them out of the vector

Find all elements with the same value in a vector, then erase all of them out of the vector


The problem is that I need to find all elements with the same value in a vector, do something with them, then erase all of them out of the vector. Keep doing that until the vector is empty.

vector L;  vector::iterator it, it2, it3;  vector vec;  unsigned Z;    // populate the vector (1, 2, 3, 4, 2, 4)  for(unsigned i = 1; i <= 4; ++i)     L.push_back(i);  for(unsigned i = 2; i <= 4; i = i + 2)     L.push_back(i);    it = L.begin();  while(it != L.end() -1){    cout<< "*it = " << *it << endl;    Z=0;    vec.clear();      it2 = it + 1;    cout<< "*it2 = " << *it2 << endl;      while(it2 != L.end()){       cout << "Loop *it2 = " << *it2 <Answer by 1201ProgramAlarm for Find all elements with the same value in a vector, then erase all of them out of the vector

The problem is with your erase call. erase does not automatically update the iterator; it returns the iterator to the next element. To fix it, you need to use

it2 = L.erase(it2);  

and later

it = L.erase(it);  

Answer by PaulMcKenzie for Find all elements with the same value in a vector, then erase all of them out of the vector


If the goal is to

  1. Process duplicates and then
  2. Erase them

there is a much easier solution to this, and that is to use std::stable_partition, along with a std::set:

#include   #include   #include   #include   #include   #include     using namespace std;    int main()  {      std::vector L = { 1, 2, 4, 3, 2, 4 };      std::set tempSet;      //...      // partition the elements, unique items on left, duplicates on right      auto divider = stable_partition(L.begin(), L.end(), [&](int n)      {          // return true if item is not in the set, false otherwise          return tempSet.insert(n).second;      });        // do something with the duplicates, for example, print them      cout << "Here are the dups:\n";      copy(divider, L.end(), ostream_iterator(cout, " "));        // get the average        // get number of duplicates        size_t numDups = std::distance(divider, L.end());        double avg = 0.0;        // compute average using std::accumulate      if ( numDups > 0 )          avg = std::accumulate(divider, L.end(), 0.0) / numDups;      cout << "\nThe average of the duplicates is: " << avg << "\n";        // erase the duplicates      L.erase(divider, L.end());        // print the updated vector now      cout << "\n\nHere is the resulting vector:\n";      copy(L.begin(), L.end(), ostream_iterator(cout, " "));  }  

Live Example

Note there are no loops in the code above. Everything is done by an algorithm function. Partitioning, average computation, erasing, etc., are all performed with no loops.

Basically we test each item to see if the item exists in the set. If it does, then it will go to the right of the partition, if not, then the item goes to the left of the partition.

The return value divider is an iterator to the element that is the "dividing line" in the partition. Once the items are partitioned, then we can process them easily by using divider to tell us where the "good" items are and where the "about to be erased" items are.

BTW, this worked the first time I compiled it successfully -- the one major reason for this "luck" in getting it to work quickly is that the algorithm functions just plain work when given the correct parameters (and if the predicate function is written correctly). Erasing items, moving items, etc. in a container, especially a sequence container such as vector, is almost always covered by usage of 1, 2, or 3 algorithm functions.

Answer by anandnilkal for Find all elements with the same value in a vector, then erase all of them out of the vector


vector L;  vector::iterator it, it2, it3;  vector vec;  unsigned Z;    // populate the vector (1, 2, 3, 4, 2, 4)  for(unsigned i = 1; i <= 4; ++i)      L.push_back(i);  for(unsigned i = 2; i <= 4; i = i + 2)      L.push_back(i);    std::set myset;  for(it = L.begin(); it != L.end(); ++it){      myset.insert(*it);  }    for(std::set::iterator iter = myset.begin();      iter != myset.end(); ++iter){      std::cout << "element = " << *iter << std::endl;      Z += *iter;  }  std::cout << "sum = " << Z << std::endl;  Z = Z/myset.size();    std::cout<< "Average value = " << Z << std::endl;  L.clear();  

Answer by Sigi Schwartz for Find all elements with the same value in a vector, then erase all of them out of the vector


This is my solution, which was inspired by PaulMcKenzie's code (please don't mind my re-using some of your lines). Just like him I didn't use any handwritten loops, but made use of STL's algorithms, which one should always consider first.

In my solution I only use another container of exactly the same type and only two simple algorithms: std::remove_if and std::find. This way the code makes the intention a little bit clearer: find duplicates and remove them. Also note the use of std::move that should come in handy when having a container of something more complex than int. In that case one may have to consider using std::find_if of course.

#include   #include   #include   #include     int main()  {      std::vector L = { 1, 2, 4, 3, 2, 4 };      using cont = decltype(L);      using vt = cont::value_type;        // find duplicates and move them to separate container      cont D;      D.reserve(L.size());      D.swap(L);      D.erase(std::remove_if(D.begin(), D.end(), [&L] (vt& value)      {          if (L.cend() == std::find(L.cbegin(), L.cend(), value))          {              L.emplace_back(std::move(value));              return true;          }          return false;      }), D.end());        // do something with the duplicates, for example, print them      std::cout << "Here are the dups:\n";      std::copy(D.cbegin(), D.cend(), std::ostream_iterator(std::cout, " "));        // print the vector now      std::cout << "\n\nHere is the resulting vector:\n";      std::copy(L.begin(), L.end(), std::ostream_iterator(std::cout, " "));        return 0;  }  

See it in action here.

Answer by Thanh for Find all elements with the same value in a vector, then erase all of them out of the vector


I finally found out the solution for my own question. The question is

  1. We have a vector L that contains many duplicated elements.
  2. We need to find all the dup elements
  3. Do something with the dup elements

My method is to use 2 iterators on L, say it and it2. it is kept at the beginning of L, while it2 will go through the vector. If *it and *it2 have the same value, then we will put *it2 into a temporary vector vec. Then, we L.erase(it2). it2 will keep moving till the end of L, collect all the dup elements into vec and delete them from L. When it2 reach the end of L, we call L.erase(it). After that, the process continues until the vector L is empty.

Here is the code that I modified. The most important thing to note is the condition in the while. I use while(it < L.end()) instead of while(it != L.end()) because when we erase an element, the iterator will somehow go pass the condition !=.

I am using an old compiler (older than C++0x) for I don't want to mess with the environment right now. Thus, it will be safe for anyone to use my code.

vector L;  vector::iterator it, it2, it3, it4;  vector vec; //temporary variable to store matched elements  float Z;    // populate the vector (1, 2, 3, 4, 1, 3)  for(unsigned i = 1; i <= 4; ++i)    L.push_back(i);    for(unsigned i = 1; i <= 4; i = i + 2)    L.push_back(i);      it = L.begin();  while(it < L.end()){    cout<< "*it = " << *it << endl;    Z=0;    vec.clear();      if(L.size() == 1){       cout << "Last element of vector = " << *it <0) {obj0.innerHTML=s.substr(0,r);obj1.innerHTML=s.substr(r+1);}


0 comments:

Post a Comment

Popular Posts

Powered by Blogger.