比较向量中的子项

时间:2014-03-05 16:40:30

标签: c++ vector std

问题概述:我使用std :: vector来保存Subject的对象。现在这个向量包含很多对象(有很多我指的是最多10-20个对象)。

这些对象具有字符串成员值,如类别 sub_category

category和sub_category都可以包含字符串,该字符串可以与其他对象的sub_category&类别。

问题:现在我希望我的std :: vector只包含那些的sub_category为唯一的对象。如果类别不是唯一的,则不是问题。

其次,如果我们发现2个对象具有相同的sub_category,那么我们必须从向量中删除其中一个。我们将根据一些规则示例删除它

删除规则如果是                   i)主题的实例 - > category =“Land”或者如果category =“Jungle”则删除其他重复的对象,
                  ii)如果上述条件不匹配,则删除其中任何一个。

我想知道,我如何比较矢量中的子项。例如

我上课说主题

class Subject
{
public :
// some constructors,
// functions to get ., set category and sub category
   std::String get_sub_category()   
   std::string get_category();

 private:
   std::string category;
  std::string sub_category;
}

我有存储主题对象的向量。示例

vector<Subject> sub_vec;

现在我想要的是从具有相同sub_category的向量中删除对象 我不是在寻找源代码,我需要一个起点,? 示例

    sub_vec[0] = Animal  object that has sub_category Tiger
    sub_vec [1] = Animal object   with Lion as sub category 
    sub_vec[2] = Forest object with sub_category Tiger

所以我想要的是基于某些条件(我可以做)移除包含Tiger的Forest或Animal对象。 但是为了那个我怎么做比较?

感谢大家的帮助。我已经编写了这个功能并进行了检查,但我确信还有很大的改进余地。请你们解决我的陷阱。

 std::vector< Subject >copy_vector; // copy_vector conatins all the objects of SUbject with redundant sub_category


  for( std::vector< Subject >::iterator ii = copy_vector.begin() ; ii != copy_vector.end() ; ++ii )
  {
      sub_category = ii->get_sub_category();

      std::cout <<" sub_category-- in main for loop " << sub_category  << std::endl ;
      std::vector< Subject >::iterator it = ii+1;
      while( it != copy_vector.end() )
      {
            std::cout <<" the  size of copy _vector is = " << copy_vector.size() << std::endl ; // for debug purpose
          if( it->get_sub_category() == sub_category )
          {
              std::cout <<" we got a match here" << std::endl ;
              // since both are duplicate , we have to delete one of them. Rules for deleting  are if 
              i) instance of Subject ->category = " Land " OR if category = "Jungle"   then delete other duplicate object , 
              ii) if above condition doesn't match then delete either of them.

              if( ( it->get_category == "Land" ) || (  it->get_category == "Jungle" )  )
              {
                 std::cout <<" we are deleting it reference value  " << std::endl ;
                 it =  copy_vector.erase(ii);

                 // increment the counter 
                 ++ii;
              }
              else if( ( ii->get_category == "Land" ) || (  ii->get_category == "Jungle" )  )
              {
                 std::cout <<" we are deleting from copy_vector  " << std::endl ;
                 it =  copy_vector.erase(it);
              }

              else
              {
                     std::cout <<" we are deleting from copy_vector  when there is no match for rules " << std::endl ;
                      it =  copy_vector.erase(it);
              }
              std::cout <<" the size of copy _vector is = " << copy_vector.size() << std::endl ;

          }
          else
          {
              std::cout <<" No Match" << std::endl;
              // increase main iterator 
              if( it != copy_vector.end() )
             {
                     ++it;
             }
          }
      }

  }
  //print value
    for( std::vector< Subject >::iterator ii = copy_vector.begin() ; ii != copy_vector.end() ; ++ii )
    {

        std::cout <<" New list = " << ii->get_category <<" \t " << ii->get_sub_category() << std::endl;
    } 

4 个答案:

答案 0 :(得分:1)

一种方法是使用remove_if。要检查对象是否具有重复的sub_category,您可以使用函数或函子来存储它在setunordered_map中找到的子类别,并删除集合中已存在其s​​ub_category的所有对象/ unordered_map。

注意,unordered_map仅在c ++ 11中可用。

答案 1 :(得分:0)

您应该使用lambda表达式或定义功能对象。

使用lambda表达式

的示例
#include <vector>
#include <string>
#include <algorithm>

// ...

std:string tiger = "Tiger";

sub_vec.erase( std::remove_if( sub_vec.begin(), sub_vec.end(), 
                               [&]( const Subject &s ) { return ( s.sub_category == tiger ); } ),
               sub_vec.end() ); 

考虑到上面的代码删除了sub_category等于“Tiger”的所有obexts。如果只需删除重复项,则首先应找到子类别的第一个对象,然后删除具有相同子类别的所有其他对象。在这种情况下,代码可能看起来像

#include <vector>
#include <string>
#include <algorithm>

// ...

std:string tiger = "Tiger";

auto equal_sb_category = [&]( const Subject &s ) { return ( s.sub_category == tiger ); };

auto it = std::find_if( sub_vec.begin(), sub_vec.end(), equal_sb_category );

if ( it != sub_vec.end() )
{
    sub_vec.erase( std::remove_if( std::next( it ), sub_vec.end(), equal_sb_category ),
                   sub_vec.end() ); 
}

答案 2 :(得分:0)

您可以尝试使用BOOST_FOREACH迭代向量元素

我正在做类似的事情:

BOOST_FOREACH( Subject f, sub_vec )
{
    ///TODO: do your filtering here 
    if(f.sub_category == "<bla bla>")
}

我喜欢使用BOOST_FOREACH的原因是它使代码非常易读,当你处理许多向量元素和许多过滤可能性时,那肯定是一个需要考虑的因素

答案 3 :(得分:0)

您的解决方案具有时间复杂度O(n * n),但问题可以通过复杂度O(n * log(n))甚至O(n)来解决。

首先,让我们定义这样的类别比较功能(如果类别是&#34; Land&#34;或&#34; Jungle&#34;那么它比其他类别更大):< / p>

bool CategoryLess(string sCategory1, string sCategory2){
    return sCategory1 != "Land" && sCategory1 != "Jungle"
        && (sCategory2 == "Land" || sCategory2 == "Jungle");
}

现在遍历向量并将所有找到的子类别和相应的主题存储在std::unordered_map(如果您不使用C ++ 11,则为std::map)。如果子类别已在map中,则替换相应的Subject,如果已找到Subject的类别少于新Subject的类别:

unordered_map<string, Subject*> Subcategories;

for (int i=0; i<sub_vec.size(); ++i){
    unordered_map<string, Subject*>::iterator
        it = Subcategories.find(sub_vec[i].get_sub_category());  

    if (it != Subcategories.end()){
        if (CategoryLess((*it)->get_category(), sub_vec[i].get_category())
            it->second = &sub_vec[i];
    }
    else
        Subcategories[sub_vec[i].get_sub_category()] = &sub_vec[i];
}

现在您拥有所有子类别和相应Subject的地图 如果我们发现两个或多个Subject具有相同的子类别,则地图包含指向具有更大类别的Subject的指针。

现在再次迭代sub_vec并删除Subject,如果

Subcategories[sub_vec[i].get_sub_category()] != &sub_vec[i];

时间复杂度:
如果我们使用std::unordered_map,则两个周期的预期时间复杂度为O(n)(在最坏的情况下为O(n * n))。
如果我们使用std::map,则两个周期的时间复杂度为O(n * log(n))。

(我没有考虑字符串比较的时间复杂性和vector.erase无关紧要)

请注意,而不是从向量中删除Subject时,可以更改其他Subject的地址。因此,在将指向Subject的指针(例如,复制需要Subject s)与另一个向量进行比较而不是从向量中删除其他Subject时,需要注意。但它并没有改变我的解决方案的总体思路。