2017-01-02 64 views
1

我对矢量相当陌生,需要一些关于矢量操作的额外帮助。2D矢量 - 通过搜索删除行

我目前已经创建了一个全局的StringArray向量,该向量由文本文件中的字符串值填充。

typedef std::vector<std::string> StringArray; 
std::vector<StringArray> array1; 

我已经创建了一个名为“删除”功能,从用户获取输入,并最终将比较输入对数组中的第一个值,看看它是否匹配。如果是这样,整行将被删除,被删除行下的所有元素将被“洗牌”到一个位置以填满游戏。

的人口阵列看起来像这样:

Test1 Test2 Test3 
Cat1 Cat2 Cat3 
Dog1 Dog2 Dog3 

而且remove函数如下:

void remove() 
{ 
    string input; 

    cout << "Enter the search criteria"; 
    cin >> input; 

我知道我需要一个循环遍历数组迭代,比较每个元素与输入值并检查它是否匹配。

我认为这将是这样的:

for (int i = 0; i < array1.size(); i++) 
{ 
    for (int j = 0; j < array1[i].size(); j++) 
    { 
     if (array1[i] = input) 
     **//Remove row code goes here** 
    } 
} 

但是,这是我的理解。我不太确定A)如果该循环是正确的,B)我将如何去删除整行(不仅仅是找到的元素)。我是否需要将array1复制到一个临时向量,丢失指定的行,然后复制回array1?

我最终要用户输入“CAT1”为例,然后我到了array1最终被:

Test1 Test2 Test3 
Dog1 Dog2 Dog3 

所有帮助表示赞赏。谢谢。

回答

1

所以你的循环几乎在那里。在使用一个索引i循环遍历外部向量,然后使用另一个索引j遍历内部向量时,您是正确的。您需要使用j才能获得与input进行比较的字符串。此外,您需要在if声明中使用==进行比较。

for (int i = 0; i < array1.size(); i++) 
{ 
    for (int j = 0; j < array1[i].size(); j++) 
    { 
     if (array1[i][j] == input) 
     **//Remove row code goes here** 
    } 
} 

然后,移除一行是一样的删除任何矢量元素,即调用array1.erase(array1.begin() + i);(见How do I erase an element from std::vector<> by index?

+1

太好了,就是我在罗比之后。我知道我有这个逻辑,只是不知道如何把它付诸实践!非常感谢您的帮助! :) – GuestUser140561

+0

他不需要内部循环,因为他只想比较每个StringArray中的第一个值。另外,如果不需要顺序操作,则可以使用StringArray键的第一项对array1使用std :: map,因此在比较输入时具有O(1)。 –

0

使用std::list<StringArray> array1;

std::vector删除的项目是低效率的,因为它必须将所有的程序数据。 列表对象将允许您从列表中删除一个项目(一行),而无需将其余行向上移动。它是一个链表,所以它不允许使用[]运算符进行随机访问。

+0

对于这个问题,操作类型的过滤仍然'O(N)'(您节省擦除,但你需要的循环无论如何做搜索)。事实上,常数因子的增益会补偿'std :: list'的问题值得商榷。 – 6502

+0

对矢量的擦除()操作的效率不仅仅是渐近复杂度的问题。诸如移动数据的存储器操作特别昂贵。事实上,由于搜索是以线性方式完成的,因此在这种情况下不需要随机访问矢量。 对'vector :: erase'的调用将触发所有后继向量的复制构造函数,并因此触发所有涉及的字符串对象。 – Jadh4v

+0

不一定是复制构造函数(可以使用移动构造函数)。谈论内存,一个'std :: vector'对缓存友好得多,并且这些元素不需要指针的额外数据。说一个'的std :: list'会更有效你需要在真实的数据实际测试之前......我不会感到惊讶,有这样的情况:它的便宜在高速缓存友好的方式将数据移动而不是在堆上随机分配的更胖的节点之间跳转。实际上,根据我的经验,'std :: list'在C++中几乎没有用处,并且很少是最好的选择。 – 6502

0

您可以使用显式循环,但你也可以利用现有的已经实施循环标准图书馆。

void removeTarget(std::vector<StringArray>& data, 
        const std::string& target) { 
    data.erase(
     std::remove_if(data.begin(), data.end(), 
      [&](const StringArray& x) { 
       return std::find(x.begin(), x.end(), target) != x.end(); 
      }), 
     data.end()); 
} 

std::find实现一个循环来搜索序列中的元素(你需要看是否有匹配的)和std::remove_if实现一个循环来“过滤掉”符合特定规则的元素。

C++ 11种标准算法之前基本上是不可用的,因为没有容易的方式来指定的自定义代码的参数(例如比较函数),你必须在它们由该算法所需的确切形式分别进行编码。

用C++ 11 lambda表达式但是现在的算法是更实用,你就不会被迫创建(并给予合理的名称),一个额外的全局类只是为了实现匹配的自定义规则。