简体   繁体   中英

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

I have a 2D std::vector < std::vector <double> > array consisting of three rows and an unknown number of columns. I would like to delete any column where the value of row 0 > row 1 . Here is my effort:

#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);

The array is initially:

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

I would like it to become:

1       1       1                                                                                                      
2       2       2                                                                                                      
3       3       3 

Instead I get:

1       1       1                                                                                                              
2       2       1       2                                                                                                      
3       3       3       3   

I imagine the problem is because the size of the array is changing as elements are deleted, invalidating the loop conditions, and/or iterators are being removed. But with this observation, I have reach my (rather circumscribed) limits.

I would be most grateful for any advice.

Your code is "correct" but does not work in-place. One solution would be to copy the array and replace it in the copy while iterating over the old one:

#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);      
}

If want to do it in-place you need to change the for-loop logic.

This solution, inspired by @RoQuOTriX, iterates over the original 2D std::vector array and selectively copies desired columns to a new array (instead of erasing undesired columns in the new array). The strategy solves the problem of iterating over a changing array.

#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);      
}

fog is:

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

and, as desired, fog2 is:

1       1       1                                                                                                              
2       2       2                                                                                                              
3       3       3 

This approach removes all columns where row 0 > row 1 , whether separated or contiguous, without causing a segmentation fault.

However, this approach is quite "heavy", requiring a deep copy. If anyone has a more efficient solution, I would love to hear it!

The following approach deletes the desired columns "in place" instead of copying. The strategy is adapted from 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);
    
}


fog before loop is:


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

And fog after loop is:


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

Perhaps surprisingly, deleting in place did not speed up the operation compared to the copy approach used by me (@Bob) above. Maybe the amount of memory jockeying ends up being similar in both approaches. However, since there is no copying with the deleting in place strategy, it is presumably more efficient in terms of memory footprint.

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