Iterator arithmetic - c++

I'm working right now with iterators arithmetic operations and stack on small problem .
I need to make a Sum of first and last element of vector<int> followed by second and last element of vector<int> , third and last element of vector<int>
Example:
Input numbers by user
1 2 3 4 5 6 7 8 9
Output should be
10 11 12 13 14 15 16 17
In general the code should do addition like that
1+9 2+9 3+9 4+9 5+9 6+9 7+9 ......
So basically i need the actual code for this arithmetic operation using iterator with member functions *.begin() , *.end() only ! I've try many ways but nothing coming in my head how to do this operation only with .begin() and .end() . I found other member functions but this functions is explained in STD library, not in basic knowledge level. So i need help to make code with only begin() and end() member functions if possible.
Code i got so far
int main()
{
vector<int> numset;
int num_input;
auto beg=numset.begin(), end=numset.end();
while (cin>>num_input)
{
numset.push_back(num_input);
}
for (auto it = numset.begin()+1; it !=numset.end(); ++it)
{
// *it=*it+1+nuset.end(); -- Wrong X
// *it+=(end-beg)/2; -- Totally wrong(and totally stupid) X
// *it + numset.back() -- can't use other member functions X
//////// I've stack here dont know what code need //////
cout<<*it<<endl;
}
Thank you for your time.

The operation you perform is *it+*(it-1). (It might help to add more parentheses and spaces in your code.) That adds two adjacent elements from the sequence.
The last element in the sequence is numset.back(). So try *it + numset.back() instead. And there's no need to start with the second element, since you do want to print the sum of the first and last elements. If you don't want to print the sum of the last element with itself, you should stop at end() - 1, though.

Related

Variables inside and outside a loop with/without asterix

I am not proficient in C++ but I am converting a short script to PHP
for(auto it = First; it != Last; ++it)
{
Result += *it;
}
From this snippet, I can speculate this simply means
Result = Result + it
where * is a reference to the pointer of the loop.
That said I see this symbol used outside of loops and in some cases I see variables without this symbol both in and outside of loops which puts holes in my theory.
Again I am trying to RTFM but I am unsure what I am searching for.
Both First and Last are iterator objects, representing a generalization of pointers in C++ Standard Library. Additionally, the two iterators reference the same collection, and Last can be reached from First by incrementing the iterator*.
Result is some sort of accumulator. If it is of numeric type, += means Result = Result + *it, where *it is whatever the iterator is pointing to. In other words, Result accumulates the total of elements of the collection between First, inclusive, and Last, exclusive. If First points to the beginning of an array and Last points to one-past-the-end of an array of numeric type, your code would be equivalent to calling PHP array_sum() on the array.
However, Result is not required to be numeric. For example, it could be a std::string, in which case += represents appending the value to the string.
* In terms of pointers and arrays this would be "pointing to the same array," and "Last points to a higher index of the array than First."
I believe your speculation is incorrect.
it, first and last are either iterators or pointers. Iterators are C++ objects that can be used to iterator over containers. For basic usage, they behave much like pointers, and can be dereferenced the same way.
For example:
std::vector<int> myList;
...
// Search for the number 10 in the list.
std::vector<int>::iterator it = std::find(myList.begin(), myList.end(), 10);
// If the number 10 was found in the list, change the value to 11.
if (it != myList.end())
*it = 11; //< Similar to pointer syntax.
In your specific example, the Result variable has a value added to it. To get that value, your code uses the * operator to get the value from the iterator.
The same concept applies to pointers. although iterators and pointers are very different concepts, accessing their values is very similar.

std::remove vector for specified element

I'm trying to remove a specific value that is defined by an if statement, then stores as an int, i want to then look through the vector and erase it by using
if (comparedValuesBetween2[i] == First0ValueFor0Number2[j])
{
//make sure if there are no values to compare left just leave the the while loop by editing the count.
comparedValuesBetween2.resize(std::remove(comparedValuesBetween2.begin(), comparedValuesBetween2.end(), 8) - comparedValuesBetween2.begin());
}
but im getting these errors and i dont know why if you could help
6 IntelliSense: too many arguments in function call g:\08227 acw\ACW\Sudoku\Sudoku\main.cpp 225
5 IntelliSense: no suitable conversion function from "std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>" to "const char *" exists g:\08227 acw\ACW\Sudoku\Sudoku\main.cpp 225
I'm very new to c++. Thanks for your help.
You can simply call std::vector::erase() to remove specified element from the container:
if (comparedValuesBetween2[i] == First0ValueFor0Number2[j])
comparedValuesBetween2.erase(comparedValuesBetween2.begin() + i);
Also, just a side note, vector.erase() returns an iterator that points the next element in the vector. So if you are traversing your vector through an iterator, you gotta make sure you don't loose track of the iterator after you delete an element in the vector.
You don't really provide enough information on what you are trying to achieve. I suppose that i and j are loop indices?
The "idiomatic" way of doing it is called remove/erase idiom:
for(int j; .....) {
...
if(....) {
comparedValuesBetween2.erase(std::remove(comparedValuesBetween2.begin(), comparedValuesBetween2.end(), First0ValueFor0Number2[j]));
}
}
It has to be refined depending on what exactly is your use-case. Ideally the loop on j should not be a raw loop as well.

Don't understand results of std::remove in C++ STL

I was reading Josuttis "The C++ Standard Library, 2nd ed.". In section 6.7.1 author explains that the code given below will give unexpected results. I still don't how std::remove() functions, and why I am getting this strange result. (Though I understood that you need to use std::erase() in order to actually remove elements, and it is actually better to use list::erase() rather than combination of std::remove() & `std::remove()).
list<int> coll;
// insert elements from 6 to 1 and 1 to 6
for (int i=1; i<=6; ++i) {
coll.push_front(i);
coll.push_back(i);
}
// print
copy (coll.cbegin(), coll.cend(), // source
ostream_iterator<int>(cout," ")); // destination
cout << endl;
// remove all elements with value 3
remove (coll.begin(), coll.end(), // range
3); // value
// print (same as above)
and the results are
pre: 6 5 4 3 2 1 1 2 3 4 5 6
post: 6 5 4 2 1 1 2 4 5 6 5 6 (???)
This explanation should help:
Removing is done by shifting the elements in the range in such a way
that elements to be erased are overwritten. Relative order of the
elements that remain is preserved and the physical size of the
container is unchanged. Iterators pointing to an element between the
new logical end and the physical end of the range are still
dereferenceable, but the elements themselves have unspecified values.
A call to remove is typically followed by a call to a container's
erase method, which erases the unspecified values and reduces the
physical size of the container to match its new logical size.
Note that the return value from std::remove() is the iterator that represents the new end. Therefore, calling std::erase() on this new end and the old end will free your excess space.
std::remove doesn't actually shorten the list. It can't - as it only gets iterators and not the container itself.
What it does is copies the remaining values so that you get them in the beginning of the container. But the final elements of the container (in your case - the last two: '5' and '6') are actually still there..
After using std::remove you have to shorten to container yourself to remove the remaining "junk" copies.
You asked the algorithm to remove "3" element. So, while enumerating the container the algo shifts the content if something is removed from the middle. Such shift occurs 2 times in your case, this is why you see "5 6" elements at the end (because actual end was moved to 2 items forward). Then, "std::erase" will fix the issue with tail zombies.
To quote from everyone's favorite c++ website:
The function cannot alter the properties of the object containing the
range of elements (i.e., it cannot alter the size of an array or a
container): The removal is done by replacing the elements that compare
equal to val by the next element that does not, and signaling the new
size of the shortened range by returning an iterator to the element
that should be considered its new past-the-end element.
So std::remove doesn't change the size of the list. It removes the matching elements and returns you an iterator that represents the new end of the list. To actually erase the extraneous elements, you then need to do:
auto it = remove(coll.begin(), coll.end(), 3);
coll.erase(it, coll.end());

Weird behaviour with vector::erase and std::remove_if with end range different from vector.end()

I need to remove elements from the middle of a std::vector.
So I tried:
struct IsEven {
bool operator()(int ele)
{
return ele % 2 == 0;
}
};
int elements[] = {1, 2, 3, 4, 5, 6};
std::vector<int> ints(elements, elements+6);
std::vector<int>::iterator it = std::remove_if(ints.begin() + 2, ints.begin() + 4, IsEven());
ints.erase(it, ints.end());
After this I would expect that the ints vector have: [1, 2, 3, 5, 6].
In the debugger of Visual studio 2008, after the std::remove_if line, the elements of ints are modified, I'm guessing I'm into some sort of undefined behaviour here.
So, how do I remove elements from a Range of a vector?
Edit: Sorry, the original version of this was incorrect. Fixed.
Here's what's going on. Your input to remove_if is:
1 2 3 4 5 6
^ ^
begin end
And the remove_if algorithm looks at all numbers between begin and end (including begin, but excluding end), and removes all elements between that match your predicate. So after remove_if runs, your vector looks like this
1 2 3 ? 5 6
^ ^
begin new_end
Where ? is a value that I don't think is deterministic, although if it's guaranteed to be anything it would be 4. And new_end, which points to the new end of the input sequence you gave it, with the matching elements now removed, is what is returned by std::remove_if. Note that std::remove_if doesn't touch anything beyond the subsequence that you gave it. This might make more sense with a more extended example.
Say that this is your input:
1 2 3 4 5 6 7 8 9 10
^ ^
begin end
After std::remove_if, you get:
1 2 3 5 7 ? ? 8 9 10
^ ^
begin new_end
Think about this for a moment. What it has done is remove the 4 and the 6 from the subsequence, and then shift everything within the subsequence down to fill in the removed elements, and then moved the end iterator to the new end of the same subsequence. The goal is to satisfy the requirement that the (begin, new_end] sequence that it produces is the same as the (begin, end] subsequence that you passed in, but with certain elements removed. Anything at or beyond the end that you passed in is left untouched.
What you want to get rid of, then, is everything between the end iterator that was returned, and the original end iterator that you gave it. These are the ? "garbage" values. So your erase call should actually be:
ints.erase(it, ints.begin()+4);
The call to erase that you have just erases everything beyond the end of the subsequence that you performed the removal on, which isn't what you want here.
What makes this complicated is that the remove_if algorithm doesn't actually call erase() on the vector, or change the size of the vector at any point. It just shifts elements around and leaves some "garbage" elements after the end of the subsequence that you asked it to process. This seems silly, but the whole reason that the STL does it this way is to avoid the problem with invalidated iterators that doublep brought up (and to be able to run on things that aren't STL containers, like raw arrays).
Erasing elements in std::vector invalidates iterators past the removed element, so you cannot use "foreign" functions that accept ranges. You need to do that in a different way.
EDIT:
In general, you can use the fact that erasing one element "shifts" all elements at further positions one back. Something like this:
for (size_t scan = 2, end = 4; scan != end; )
{
if (/* some predicate on ints[scan] */)
{
ints.erase (ints.begin () + scan);
--end;
}
else
++scan;
}
Note that std::vector isn't suited for erasing elements in the middle. You should consider something else (std::list?) if you do that often.
EDIT 2:
As clarified by comments, first paragraph is not true. In such case std::remove_if should be more efficient than what I suggested in the first edit, so disregard this answer. (Keeping it for the comments.)
The behavior isn't weird - you're erasing the wrong range. std::remove_if moves elements it "removes" to the end of the input range. In this case, what you're looking for would be to do:
ints.erase(it, ints.begin() + 4 /* your end of range */);
From C++ in a Nutshell:
The remove_if function template
"removes" items for which pred returns
false from the range [first, last).
The return value is one past the new
end of the range. The relative order
of items that are not removed is
stable.
Nothing is actually erased from the
underlying container; instead, items
to the right are assigned to new
positions so they overwrite the
elements for which pred returns false.
See Figure 13-13 (under remove_copy)
for an example of the removal process.

Can you embed for loops (in each other) in C++

I am working on a merge sort function. I got the sort down - I am trying to get my merge part finished. Assume that I am learning C++, have cursory knowledge of pointers, and don't understand all the rules of std::vector::iterator's (or std::vector's, for that matter).
Assume that num is the size of the original std::vector that have copied (std::copy) values from an array of size "int ar[num]." Assume that farray has the values of (0 to (num / 2)) and sarray has the values of ((num / 2) to num).
int num = original.size();
std::vector<int> final(num);
for (std::vector<int>::iterator it = farray.begin(); it != farray.end(); ++it) {
for (std::vector<int>::iterator iter = sarray.begin(); iter != sarray.end(); ++iter) {
if (*it > *iter) final.push_back(*it);
else
final.push_back(*iter);
}
}
This code compiles and my latest stable build of Bloodshed Dev-C++ does not throw any warnings or errors. I don't know if this is valid, I still need to try and cout all the values of final. I just want to know if this is common, prone to errors, or just bad style. And, if so, how you would
It's valid... but a for loop probably isn't what you want. When you use two for loops, your inner loop keeps going back to the start every time the outer loop loops. So if your vectors contain:
farray: 10 9 8 4 3
sarray: 7 6 4 3 1
Then your final array will contain something like:
10 10 10 10 10 9 9 9 9 9 8 8 8 8 8 7 6 4 4 4 7 6 4 3 3
because you are testing every single combination, and adding the larger one to the final list. A better solution might be to remember an iterator for each list, and just use one loop. Rather than looping over a list, just go through both of them together - if sarray has the larger number, then increment your sarray iterator, and compare that with the old farray iterator. Stop your loop when both sarray and farray are empty.
vector<int> fiter = farray.begin();
vector<int> siter = sarray.begin();
vector<int> final;
// Let's traverse both farray and sarray.
// We'll want to stop this loop once we've traversed both lists.
while (fiter != farray.end() && siter != sarray.end())
{
if (fiter == farray.end())
{
// we must have gone right through farray -
// so use the value from sarray, and go to the next one
final.push_back(*siter);
siter++;
}
else if (siter == sarray.end())
{
// we must have gone right through sarray -
// so use the value from farray, and go to the next one
final.push_back(*fiter);
fiter++;
}
else if (*siter > *fiter)
{
// siter is the bigger of the two - add it to the final list, and
// go to the next sarray entry
final.push_back(*siter);
siter++;
}
else // *fiter >= *siter
{
// fiter is the bigger of the two - add it to the final list, and
// go to the next farray entry
final.push_back(*fiter);
fiter++;
}
}
I haven't tested it - and if this is for homework, then please try to understand what I've done, go away and write it yourself, rather than copy+paste.
Merge sort algorithm aside, nested for loop with iterator's is just as valid as nested for loops with two variables i and j.
You can nest loops of any kind (for, while, do while) as long as you don't reuse the loop variables. If you would try that it would compile but may fail miserably during runtime. Although technically allowed to use the same name for nested loop variables in modern C and C++ it is confusing and should be avoided.
It's no more or less prone to errors than a single loop except for the already mentioned problem with the reuse of loop variables.
Read more about the limits of nested loops.
Nesting for loops is a totally legit way to do things. For example, it's the classic "old school" way to traverse a 2D array - one loop goes down the y axis, and the other loop goes down the x axis.
Nowadays, with those kids and their for each loops and iterators and mapping functions there are arguably "better" ways to do it, (for some definition of better) but nesting loops works just fine. Using C++ or pointers doesn't change that.
Yes, you can do this. And yes, it is often prone to errors. In fact, writing loops is itself prone to errors, which is one argument to use the algorithms in the STL like for_each, copy and transform.
Yes, you can nest loops, or other statements, to pretty much whatever depth you want (within reason; there are limits, as mentioned in another answer, but they're way above what you should ever need).