-3

I need to do convert std::vector<std::vector<T>> to std::vector<T> (line by line) in a lot of places in my code. I obviously know how to implement it by myself, but is there any short-code solution in boost or stl? (i can use only C++98)

UPD: I need some very short solution, like single line call of some function (may be with boost lambda), without loops, so solution from C++ pushing elements of a vector of vectors into a vector is not acceptable.

UPD2: please, do not post the answers with loops, i know how to do that. The question is in short-code way, not in idea.

Community
  • 1
  • 1
brachistochron
  • 321
  • 1
  • 11
  • possible duplicate of [C++ pushing elements of a vector of vectors into a vector](http://stackoverflow.com/questions/18875334/c-pushing-elements-of-a-vector-of-vectors-into-a-vector) – NathanOliver Apr 14 '15 at 14:22
  • Do you still need the original vector of vectors intact after the call? – Bathsheba Apr 14 '15 at 14:27
  • 2
    I don't see how this could be done without a loop. – NathanOliver Apr 14 '15 at 14:32
  • @NathanOliver, trough already implemented traversers, for example – brachistochron Apr 14 '15 at 14:38
  • @brachistochron Could you provide any sort of example of that? – NathanOliver Apr 14 '15 at 14:39
  • 1
    Flattening. See http://stackoverflow.com/a/9252979/85371; http://ericniebler.com/2014/04/27/range-comprehensions/; http://stackoverflow.com/questions/3623082/flattening-iterator – sehe Apr 14 '15 at 15:08
  • @brachistochron Could you help me understand why you need this in one line? Or if not that, then why you can't use C++11? – Jonathan Mee Apr 14 '15 at 15:08
  • 1
    If a person needs this in a lot of places they either need to use the data (iterating it) or they need to present it to some API in contiguous form. In the latter case, it would be better to redesign the storage so that the layout flipping isn't required (multi-array?). In the first place you'd provide one custom iterator and use standard algorithms from there – sehe Apr 14 '15 at 15:22

2 Answers2

3

Since it is in a lot of places, it might be good idea to write your own small wrapper function to put it in all those places. The logic inside wrapper can be customized based on performance, as it is now in single place. The simplest probably would be

inline template <typename T> 
std::vector<T> to_vector(const std::vector<std::vector<T>>& double_vec) {
  std::vector<T> output;
  for(std::vector<std::vector<T>>::size_type i=0; i < double_vec.size(); ++i) {
    output.insert(output.end(), double_vec[i].begin(), double_vec[i].end());
  }
  return output;
}

Which can be customized/optimized if necessary.

Ilya Kobelevskiy
  • 5,245
  • 4
  • 24
  • 41
  • As i said, i know, how to make it by myself. I need some solution where will be called some one function (some traverser, for example) WITHOUT a loop. Read question carefully, please. – brachistochron Apr 14 '15 at 14:40
  • I disagree; this is a good answer apart, perhaps, from the use of `size_t` as opposed to `vector::size_type` and a reliance on return value optimisation. – Bathsheba Apr 14 '15 at 14:44
  • @brachistochron Well, there was no condition about loops when I answered :). Either way, you need to access each element of original vector once to copy it, so there would be loop anyways - traversing through some boost lambda would just hide the loop. Proposed solution essentially does the same - exposes short function at call site, encapsulating converion logic in a single place :) – Ilya Kobelevskiy Apr 14 '15 at 14:54
  • @Bathsheba, Thanks for your comment, I've updated for vector::size_type. Regarding return value optimization - I think it is fair to rely on it with modern compilers for simplicity of interface, as alternative of returning by pointer adds boilerplate code - unless you know that there is no return value optimization in the case you are using. – Ilya Kobelevskiy Apr 14 '15 at 14:59
1

There is no way to do this without a loop, in fact, the task is pretty much a poster child for using a loop. Well, nested loops if we're being pedantic.

What you can do is hide the fact that you're looping by using higher level constructs, but the underlying implementation will be, well, a set of nested loops.

template <typename T>
struct flatten_functor
{
   flatten_functor(std::vector<T> &out)
     : m_out(out)
   {}

   bool operator()(std::vector<T> const& to_append)
   {
      m_out.insert(m_out.end(), to_append.begin(), to_append.end());
      return true;
   }
private:
  std::vector<T>& m_out;
};

template <typename T>
std::vector<T> flatten_vector(std::vector<std::vector<T> > const &in)
{
  std::vector<T> retval;
  flatten_functor<T> flatten_this(retval);

  std::for_each(in.begin(), in.end(), flatten_this);

  return retval;
}

As you can see that's a heck of a lot of effort to not really hide the fact that you're dealing with a loop. I don't think it's even more readable than the loop, but then again I'm using C++11 most of the time these days and it's easier to clean up this code using lambdas.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70