2017-01-02 133 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表達式但是現在的算法是更實用,你就不會被迫創建(並給予合理的名稱),一個額外的全局類只是爲了實現匹配的自定義規則。