根据 C++ 中同一列中 2 行的比较,删除 2D std::vector 中的列

Delete column in 2D std::vector depending on comparison of 2 rows in same column in C++

我有一个二维 std::vector < std::vector <double> > 数组,由三行和未知数量的列组成。我想删除值 row 0 > row 1 的任何列。这是我的努力:

#include <iostream>
#include <vector>

using namespace std;

template <typename T>
inline void printArray (const std::vector< std::vector< T > >& key_array) {
    for (int i = 0; i < key_array.size(); i++) {
        for (int j = 0; j < key_array[i].size(); j++) {
            std::cout << key_array[i][j] << "\t";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

int main()
{
    std::vector< std::vector <int> > fog {{1,1,2,1},{2,2,1,2},{3,3,3,3}};
    
    printArray(fog);
    
    for (int i = 0; i < fog[0].size(); ++i) {
                for (int j = 0; j < fog.size(); ++j) {
                    if (fog[0][i] > fog[1][i]) {
                        fog[j].erase(fog[j].begin() + i);
                    }
                }
            }
            
    printArray(fog);

数组初始为:

1       1       2       1                                                                                                      
2       2       1       2                                                                                                      
3       3       3       3 

我希望它变成:

1       1       1                                                                                                      
2       2       2                                                                                                      
3       3       3 

相反,我得到:

1       1       1                                                                                                              
2       2       1       2                                                                                                      
3       3       3       3   

我想这个问题是因为数组的大小随着元素的删除而改变,使循环条件无效,and/or 迭代器被删除。但是通过这种观察,我已经达到了我的(相当有限的)极限。

如有任何建议,我将不胜感激。

您的代码“正确”,但不能就地运行。一种解决方案是复制数组并将其替换为副本,同时迭代旧数组:

#include <iostream>
#include <vector>

using namespace std;

template <typename T>
inline void printArray (const std::vector< std::vector< T > >& key_array) 
{
    for (int i = 0; i < key_array.size(); i++) {
        for (int j = 0; j < key_array[i].size(); j++) {
            std::cout << key_array[i][j] << "\t";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

int main()
{
    std::vector< std::vector <int> > fog {{1,1,2,1},{2,2,1,2},{3,3,3,3}};
    
    printArray(fog);
    
    auto fog2 = fog;

    for (int i = 0; i < fog[0].size(); ++i) 
    {
        for (int j = 0; j < fog.size(); ++j) 
        {
            if (fog[0][i] > fog[1][i]) 
            {
                fog2[j].erase(fog2[j].begin() + i);
            }
        }
    }
    
    printArray(fog2);      
}

如果想就地执行,您需要更改 for 循环逻辑。

此解决方案受@RoQuOTriX 启发,迭代原始二维 std::vector 数组并有选择地将所需列复制到新数组(而不是擦除新数组中不需要的列)。该策略解决了迭代不断变化的数组的问题。

#include <iostream>
#include <vector>


template <typename T>
inline void printArray (const std::vector< std::vector< T > >& key_array) 
{
    for (int i = 0; i < key_array.size(); i++) {
        for (int j = 0; j < key_array[i].size(); j++) {
            std::cout << key_array[i][j] << "\t";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

int main()
{
    std::vector< std::vector <int> > fog {{1,2,1,2,2,1},{2,1,2,1,1,2},{3,3,3,3,3,3}};
    
    printArray(fog);
    
    std::vector< std::vector < double > > fog2(fog.size());

    for (int i = 0; i < fog[0].size(); ++i) {
                for (int j = 0; j < fog.size(); ++j) {
                    if (fog[0][i] < fog[1][i]) {
                        fog2.at(j).push_back(fog[j][i]);
                                }
                            }
                        }
    
    printArray(fog2);      
}

雾是:

1       2       1       2       2       1                                                                                      
2       1       2       1       1       2                                                                                      
3       3       3       3       3       3  

并且,根据需要,fog2 是:

1       1       1                                                                                                              
2       2       2                                                                                                              
3       3       3 

此方法会删除 row 0 > row 1 中的所有列,无论是分开的还是连续的,而不会导致分段错误。

但是这种方式比较“重”,需要深拷贝。如果有人有更有效的解决方案,我很想听听!

以下方法“就地”删除所需的列,而不是复制。该策略改编自How to delete column in 2d vector, c++

#include <iostream>
#include <vector>

using namespace std;

template <typename T>
inline void printArray (const std::vector< std::vector< T > >& key_array) {
    for (int i = 0; i < key_array.size(); i++) {
        for (int j = 0; j < key_array[i].size(); j++) {
            std::cout << key_array[i][j] << "\t";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

int main()
{
    std::vector< std::vector <int> > fog {{2,1,1,2,1,2,1,2,1,2},{1,2,2,1,2,1,2,1,2,1},{3,3,3,3,3,3,3,3,3,3}};
    
    printArray(fog);
    
    
    for (int i = 0; i < fog[0].size(); ++i)
        {
            
            if (fog[0][i] > fog[1][i]) {
                    
                    /* // Alternative
                    std::for_each(fog.begin(), fog.end(), [&](std::vector<int>& row) {
                            row.erase(std::next(row.begin(), i));
                        });
                     */
                    
                   for(auto& row:fog) row.erase(std::next(row.begin(), i));
                
                // accounts for deleted column
                --i;
            }
        }
    
    printArray(fog);
    
}


循环前的雾是:


2   1   1   2   1   2   1   2   1   2   
1   2   2   1   2   1   2   1   2   1   
3   3   3   3   3   3   3   3   3   3

循环后的雾是:


1   1   1   1   1   
2   2   2   2   2   
3   3   3   3   3   

也许令人惊讶的是,与上面我(@Bob)使用的复制方法相比,就地删除并没有加快操作速度。也许两种方法中内存占用的数量最终是相似的。但是,由于没有使用原地删除策略进行复制,因此它在内存占用方面可能更有效。