stl vector assign vs insert - c++

I understand the semantics of the 2 operations ,
assign- erases before replacing with supplied values.
insert - inserts values at specified location(allocates new memory if necessary).
Apart from this is there any reason to preffer one over the other?
Or to put it another way, is there any reason to use assign instead of insert.

If you wish to invoke the semantics of assign, call assign - if you wish to invoke the semantics of insert, call insert. They aren't interchangeable.
As for calling them on an empty vector, the only difference is that you don't need to supply an iterator to insert at when you call assign. There may be a performance difference, but that's implementation specific and almost certainly negligable.

assign and insert are only equivalent if the vector is empty to begin with. If the vector is already empty, then it's better to use assign, because insert would falsely hint to the reader that there are existing elements to be preserved.

assign() will blow away anything that's already in the vector, then add the new elements. insert() doesn't touch any elements already in the vector.
Other than that, if the vector you are modifying starts out empty, there is little difference.

insert() will insert the elements at a particular position. It can be a single value, or multiple values using first and last iterators. Its like inserting more elements in front of a position.
assign() will just assign the values starting at beginning till end as per input agruments "InputIterator first and InputIterator last ". This will remove all existing elements and instead populate the vector with new values as per range provided in its arguments.

Related

How do I replace a range with another range in a vector?

I want to replace a range of elements in a vector by a single other element (built from that range, but it doesn't matter). I'd like to do so without erasing first and inserting then, for all subsequent elements would me moved twice.
I figured we could generalize that with the replacement of a range by another range, whatever their sizes. Replace an empty range with something and you get insert. Replace something with an empty range and you get erase.
Anyways replace seems not to do that. It replaces all or some elements in a rage with copies of the given element. No moving around.
swap_ranges swaps elements one by one, no erase or insert either.
Have I missed an algorithm for that? Maybe a member function?
Maybe I should use list then?
I want to replace a range of elements in a vector by a single other element
As far as I know, there is no algorithm for this in standard library. But it can be fairly simply be built on top of the existing ones: Remove all except first of the range. Assign the element that wasn't removed. In the special case of empty range, insert instead of assigning. Return iterator to the beginning of the removed elements (iterator to end in case nothing was removed) so that the caller can erase them.
I figured we could generalize that with the replacement of a range by another range
This works pretty much the same as the single insert variation, but is more complex. Replace assignment with std::copy, and take into consideration that there is also a case where you both assign (copy) and insert a subrange depending on lengths of the input ranges.
The order assignment, remove, insert does not matter.
This is an algorithm that can't be done with "just iterators".
To change the size of the underlying sequence, you need to be able to call insert or erase on the underlying container.
So even though you might want to write something like:
template <typename Iter1, typename Iter2>
void replaceRange (Iter1 s_first, Iter1 s_last, Iter2 d_first, Iter2 d_last);
it won't ever work (except for the cases where the sizes are the same)

Vector vs Set Efficiency

I'm working with a large dataset. When inserting elements one by one to a set, or to a vector, I had the following confusion (in C++):
Should I reserve enough space for the vector before insertion, and then add to the vector one by one?
Or, should I insert the elements to a set one by one (since insertion to a set is faster than that of a vector) and then that set at once to a vector?
Which one would be more time-efficient?
Should I reserve enough space for the vector before insertion, and
then add to the vector one by one?
Yes. By allocating space for all required vector elements you will be avoiding additional memory allocations and memory copying. Use the vector only if you don't need the elements in any particular order and if you will only add elements to the end of the vector. Inserting elements somewhere in the middle is very inefficient because the vector stores all elements in contiguous memory and would therefore need to move all elements after the insertion point out of the way before inserting the new element.
Or, should I insert the elements to a set one by one (since insertion
to a set is faster than that of a vector) and then that set at once to
a vector?
If you need elements to be in a specific order then you should use the set. The set will place elements into the "right" place efficiently, assuming that your elements are of a type that set understands (for example, numerical types or string), otherwise you may need to write your own comparison function. Alternatively, if you have more complex data but can identify a sort-able key value then you may want to look at map instead of set. - Afterwards, you can't initialize a vector from a set "at once"; you would need to loop through the set and append to the vector.
Which one would be more time-efficient?
Considering that you have a large amount of data as input and assuming that the data is in random order:
If you don't care about the order of elements then calling push_back on a vector is most likely faster.
If you plan to insert elements somewhere in the middle then the set is most likely faster, probably even if you need to transfer the data to a vector in a second step.
All this depends a bit on the type of data, the potential comparison that you may want to perform, the implementation of the standard library and the compiler.
Now that you know the expected result I suggest that you try both. Test and measure!

insert in C++ vector

I want to insert a bit from a bitset in the beginning of a vector. I am having a hard time understanding how to do that. Here is how I think I can do it:
keyRej.insert(x, inpSeq[0]);
I don't know what to put in the place of x?
I don't know what to put in the place of x?
An iterator to the position you want to insert in:
keyRej.insert(keyRej.begin(), inpSeq[0]);
Semantically, the inserted element goes before the iterator passed as first argument. But this will result in all elements of the vector having to be moved across one position, and may also incur a re-allocation of the vector's internal data storage block. It also means that all iterators or references to the vector's elements are invalidated.
See this reference for std::vector::insert for more information.
Note that there are containers, such as std::deque, for which appending elements to the front is cheap, and reference (but not iterator) validity is maintained.
x is an iterator according to the documentation you probably read here, the new object is insert just before it.
keyRej.insert(keyRej.begin(), inpSeq[0]);

How to change a set element?

I want to change the element in a set, so I used set<T>::iterator. However, the compiler argues "the element is const". Then I realized that set<T>::iterator is a const_iterator...
So, how I can change the element? Erase it and then insert a new one?
The elements of the set will be in sorted order. If you are allowed to modify an element, then this sorting order can not be maintained. Hence you can not modify the item. You need to erase the existing element and insert a new one.
Set elements are constant and may not be modified in place. Modification could change the ordering predicate without changing the position of the element which would violate the constraints of the data structure.
However now in the future (C++17), modifying the element without erasure is possible with the extract member function:
std::set<std::string> stringset{"a", "b", "c"};
auto node = stringset.extract(stringset.begin());
std::string& str = node.value();
str = "d";
stringset.insert(std::move(node));
There is still the cost of list operations but the object itself is not destroyed or copied.
EDIT: You cant add an element to a specific location in set. the set should be in the sorted order whatever operations you do. So you have to erase the specific element and insert the new element so that the ordering of set isnt lost.
Also read more about set!

dynamic vector-like container but whose elements save their indexes?

All the elements should have fixed position in the array after insertion until I explicitly delete them from there. Is there something like this in boost or wherever? Thanks
Use an unordered_map<int, T> or map<int, T>.
Or, use a vector<optional<T>>, and set the slot to delete to none_t, instead of actually deleting it.
Instead of "deleting" an element, you want to set its value to null (or some other "no value" equivalent). Then everything stays constant as you require.
Interesting. Is your goal is to expose a mapping from integers to SLOTS, where those SLOTS may contain a value? Or is your goal to preserve the underlying address of each element and the underlying address of the start of the internal array itself? Presumably you have a reason that you need either the position of the elements or the mapping from integer keys to elements to be preserved after an element is "removed". What is that reason?
The map<> or vector<> implementations mentioned above may not work because the remove, erase, find, etc. operations will remove, rearrange, or inspect the integers which you consider to be "removed".
Unfortunately, I think this may be a case where you need to roll your own using a wrapper around vector<optional<T> > or vector<T*>, depending upon how you define remove.