3

Here is a sample vector

vector<string> v;
v.push_back("one");
v.push_back("two");
v.push_back("three four");
v.push_back("five");

// print

one
two
three four
five

i need to split the element number 3 so now the vector look (without creating another vector)

// print

one
two
three
four
five

Should i use iterator or simple loop? it should have good performance too.

duckduckgo
  • 1,142
  • 1
  • 15
  • 30
  • 3
    Maybe std::list would be a better data structure for this problem (better performances). Or you are unable to avoid std::vector? – Ante Jul 21 '14 at 08:04
  • 2
    Why not a simple loop *using* iterators? Also read about [`std::vector::insert`](http://en.cppreference.com/w/cpp/container/vector/insert). But like Ante says, for insertions in the middle of the container then [`std::vector`](http://en.cppreference.com/w/cpp/container/vector) is not the best one, [`std::list`](http://en.cppreference.com/w/cpp/container/list) is much better for that. The question you need to ask yourself is: Will this be common? – Some programmer dude Jul 21 '14 at 08:05
  • I should try lists, thanks for pointing me in right direction. Btw i if some element is deleted or created in the middle do we need to recalculate iterators? i am really dumb on this! – duckduckgo Jul 21 '14 at 08:14
  • @treemonster19 YFor vectors, then yes. When you add or remove elements from a vector the iterators are invalidated. For a list, only the iterator to the element you remove will be invalid, all other iterators will not be. – Some programmer dude Jul 21 '14 at 08:20
  • 1
    @treemonster19 for the deletion case, consider having a look at [stdvector-iterator-invalidation](http://stackoverflow.com/questions/3747691/stdvector-iterator-invalidation), for insert and friends, [does-stdvectorinsert-invalidate-iterators-if](http://stackoverflow.com/questions/14820835/does-stdvectorinsert-invalidate-iterators-if-the-vector-has-enough-room-c) and generically definitively the [iterator-invalidation-rules](http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – wonko realtime Jul 21 '14 at 08:20
  • 1
    My general approach would be 1. find the postion of the element to split. 2. split it. 3. create a new vector copying the elements from beg up to split position. 4. append the split elements. 5. copy the elements from the split position to the end. A list is optimised for insertions like this but it will depend on the size of the container as small sized vectors are fast at being copied – EdChum Jul 21 '14 at 08:36
  • @wonkorealtime thanks for the similar link, my problem is now solved. – duckduckgo Jul 21 '14 at 08:41
  • @Ante I'd be very surprised if `std::list` outperformed `std::vector` for this. – James Kanze Jul 21 '14 at 10:30
  • 1
    @JoachimPileborg `std::list` clearly has the advantage of not invalidating the iterators; depending on how he's looping, however, he may need additional logic (or not) to avoid revisiting an element. – James Kanze Jul 21 '14 at 10:31

1 Answers1

0

As has been pointed out in the comments, if you're inserting elements into the vector (which you will be), you have to avoid using an invalidated iterator. Still, something along the lines of the following should work:

std::vector<std::string> iter = v.begin();
while ( iter != v.end() ) {
    std::string::iterator breakpoint = std::find( iter->begin(), iter->end(), ' ' );
    if ( breakpoint == iter->end() ) {
        ++ iter;
    } else {
        std::string next( breakpoint + 1, iter->end() );
        iter->erase( breakpoint, iter->end() );
        iter = v.insert( iter + 1, next );
    }
}

In such cases, I generally prefer generating into a copy, however.

James Kanze
  • 142,482
  • 15
  • 169
  • 310
  • This solution is fine if std::vector is must have. But still I don't understand why std::vector would outperform std::list? Inserting elements in positions other than the vector end causes the container to relocate all the elements that were after position to their new positions? Insertion in vector generally is O(n) operation, while in list it is O(1) – Ante Jul 21 '14 at 12:28
  • 2
    @Ante The simple answer is because it does, unless the vector is inordinately large or the objects incredibly expensive to copy. Constant factors matter: allocation is expensive, and `std::list` allocates for each element; locality is important, and `std::vector` keeps all of its data adjacent. I've had the occasion to actually measure a couple of times, and each time, `std::vector` beat `std::list` hands down, including when there were insertions and removals at arbitrary locations. – James Kanze Jul 21 '14 at 12:33
  • yes it's true for small objects, mainly because of caching in modern systems. But it sounds weird when you are saying insertion in std::vector is faster then std::list, people can conclude that it is always like that. Never mind, as you said it's faster for small arrays and objects, but usually when people want good performances they are asking it because they have large scale problem (big data scale). Nice article regarding this topic: http://baptiste-wicht.com/posts/2012/11/cpp-benchmark-vector-vs-list.html – Ante Jul 21 '14 at 12:54
  • @Ante Both caching and the allocation/free play a role. It's impossible to say up front which will be faster, and in many cases, which will be faster will change from one machine to the next. In general, I've found the best solution is go with `std::vector` (assuming you don't need the stability of the iterators), and try other things if performance becomes an issue. And to pretty much ignore O(), which is predicated on individual operations having constant time, which just isn't the case today. – James Kanze Jul 21 '14 at 13:35
  • @Ante if the subsequent access time for vectors will be better than lists then, using a vector can be preferred, in a overall performance improve strategy. – duckduckgo Jul 22 '14 at 03:59