简体   繁体   中英

Finding the intersection of two vectors of strings

I have two vectors of strings and want to find the strings which are present in both, filling a third vector with the common elements. EDIT: I've added the complete code listing with the respective output so that things are clear.

  std::cout << "size " << m_HLTMap->size() << std::endl;

  /// Vector to store the wanted, present and found triggers
  std::vector<std::string> wantedTriggers;
  wantedTriggers.push_back("L2_xe25");
  wantedTriggers.push_back("L2_vtxbeamspot_FSTracks_L2Star_A");
  std::vector<std::string> allTriggers;

  // Push all the trigger names to a vector
  std::map<std::string, int>::iterator itr = m_HLTMap->begin();
  std::map<std::string, int>::iterator itrLast = m_HLTMap->end();
  for(;itr!=itrLast;++itr)
  {
    allTriggers.push_back((*itr).first);
  }; // End itr

  /// Sort the list of trigger names and find the intersection
  /// Build a typdef to make things clearer
  std::vector<std::string>::iterator wFirst = wantedTriggers.begin();
  std::vector<std::string>::iterator wLast = wantedTriggers.end();
  std::vector<std::string>::iterator aFirst = allTriggers.begin();
  std::vector<std::string>::iterator aLast = allTriggers.end();

  std::vector<std::string> foundTriggers;

  for(;aFirst!=aLast;++aFirst)
  {
    std::cout << "Found:" << (*aFirst) << std::endl; 
  };

  std::vector<std::string>::iterator it;

  std::sort(wFirst, wLast);
  std::sort(aFirst, aLast);
  std::set_intersection(wFirst, wLast, aFirst, aLast, back_inserter(foundTriggers));

  std::cout << "Found this many triggers: " << foundTriggers.size() << std::endl;
  for(it=foundTriggers.begin();it!=foundTriggers.end();++it)
  {
    std::cout << "Found in both" << (*it) << std::endl;
  }; // End for intersection

The output is then

Here is the partial output, there are over 1000 elements in the vector so I didn't include the full output:

Found:L2_te1400
Found:L2_te1600
Found:L2_te600
Found:L2_trk16_Central_Tau_IDCalib
Found:L2_trk16_Fwd_Tau_IDCalib
Found:L2_trk29_Central_Tau_IDCalib
Found:L2_trk29_Fwd_Tau_IDCalib
Found:L2_trk9_Central_Tau_IDCalib
Found:L2_trk9_Fwd_Tau_IDCalib
Found:L2_vtxbeamspot_FSTracks_L2Star_A
Found:L2_vtxbeamspot_FSTracks_L2Star_B
Found:L2_vtxbeamspot_activeTE_L2Star_A_peb
Found:L2_vtxbeamspot_activeTE_L2Star_B_peb
Found:L2_vtxbeamspot_allTE_L2Star_A_peb
Found:L2_vtxbeamspot_allTE_L2Star_B_peb
Found:L2_xe25
Found:L2_xe35
Found:L2_xe40
Found:L2_xe45
Found:L2_xe45T
Found:L2_xe55
Found:L2_xe55T
Found:L2_xe55_LArNoiseBurst
Found:L2_xe65
Found:L2_xe65_tight
Found:L2_xe75
Found:L2_xe90
Found:L2_xe90_tight
Found:L2_xe_NoCut_allL1
Found:L2_xs15
Found:L2_xs30
Found:L2_xs45
Found:L2_xs50
Found:L2_xs60
Found:L2_xs65
Found:L2_zerobias_NoAlg
Found:L2_zerobias_Overlay_NoAlg
Found this many triggers: 0

Possible Reason

I am starting to think that the way in which I compile my code is to blame. I am currently compiling with ROOT (the physics data analysis framework) instead of doing a standalone compile. I get the feeling that it doesn't work all that well with the STL Algorithm library and that's the cause of the issue, especially given how many people seem to have the code working for them. I will try to do a stand-alone compilation and re-running.

Passing foundTriggers.begin() , with foundTriggers empty, as the output argument will not cause the output to be pushed onto foundTriggers . Instead, it will increment the iterator past the end of the vector without resizing it, randomly corrupting memory.

You want to use an insert iterator:

std::set_intersection(wFirst, wLast, aFirst, aLast, 
    std::back_inserter(foundTriggers));

UPDATE: As pointed out in the comments, the vector is resized to be at least large enough for the result, so your code should work. Note that you should use the iterator returned from set_intersection to indicate the end of the intersection - your code ignores it, so you will also iterate over the empty strings left at the end of the output.

Could you post a complete test case so that we can see whether the intersection is actually empty or not?

Your allTrigers vector is empty, afterall. You never reset itr to the beginning of the map when you're filling it.

EDIT:

Actually, you never reset aFirst :

for(;aFirst!=aLast;++aFirst)
  {
    std::cout << "Found:" << (*aFirst) << std::endl; 
  };

  // here aFirst == aLast

  std::vector<std::string>::iterator it;

  std::sort(wFirst, wLast);
  std::sort(aFirst, aLast);  // **** sorting empty range ****
  std::set_intersection(wFirst, wLast, aFirst, aLast, back_inserter(foundTrigger));
                               //      ^^^^^^^^^^^^^^
                               // ***** empty range *****

I hope you can now see why it is good practice to narrow down the scope of your variables.

You never use the return value of set_intersection . In this case you could use it to resize foundIterators after set_intersection has returned, or as the upper limit of the for loop. Otherwise your code seems to work. Can we see a full compilable program and its actual output please?

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