Home > Net >  Is it possible to iterate through a vector of vectors columnwise?
Is it possible to iterate through a vector of vectors columnwise?

Time:10-28

I have a vector of vectors of strings. I want to find the lengths of the longest string in each column. All the subvectors are of the same length and have an element stored in it, so it would be rather easy to find it with two for loops and reversed indices.

vector<vector<string>> myvec = {
                                { "a", "aaa",   "aa"},
                                {"bb",   "b", "bbbb"},
                                {"cc",  "cc",  "ccc"}
                               };

But is it possible to do it with iterators without using indices?

CodePudding user response:

What about something like this?

std::vector<std::size_t> max_lengths(myvec.front().size(), 0);
for (auto const& strings : myvec) {
    std::transform(max_lengths.begin(), max_lengths.end(), strings.begin(), max_lengths.begin(),
        [](std::size_t l, std::string const& s) {
            return std::max(l, s.size());
        }
    );
}

Demo

CodePudding user response:

Assuming the inner vectors are all the same length, you can have something like

template <typename T>
class columnwise {
    std::vector<std::vector<T>> * underlying;
    struct proxy {
        std::vector<std::vector<T>> * underlying;
        std::vector<T>::difference_type offset;
        struct iterator {
            std::vector<std::vector<T>>::iterator outer;
            std::vector<T>::difference_type offset;
            using reference = typename std::vector<T>::reference;
            using pointer = typename std::vector<T>::pointer;
            iterator operator  () {   outer; return *this; }
            reference operator*() { return *(outer->begin()   offset); }
            pointer operator->() { return (outer->begin()   offset).operator->(); }
            bool operator==(iterator rhs) { return (outer == rhs.outer) && (offset == rhs.offset); }
        };
    public:
        iterator begin() { return { underlying->begin(), offset }; }
        iterator end() { return { underlying->end(), offset }; }
    };
    struct iterator {
        // member type aliases
        std::vector<std::vector<T>> * underlying;
        std::vector<T>::difference_type offset;
        iterator operator  () {   offset; return *this; }
        proxy operator*() { return { underlying, offset }; }
        bool operator==(iterator rhs) { return (underlying== rhs.underlying) && (offset == rhs.offset); }
    };
    std::vector<T>::difference_type inner_size() { if (auto it = underlying->begin(); it != underlying->end()) { return it->size(); } return 0; }
public:
    columnwise(std::vector<std::vector<T>> & vec) : underlying(&vec) {}
    iterator begin() { return { underlying, 0 }; }
    iterator end() { return { underlying, inner_size() }; }
};

Which iterates as you expect.

  • Related