Related
I've been trying to work this out for more than an hour. I need to move an integer from middle of the list to the beginning. There is no option for moving an integer, it would be fine if I could insert one at the beginning and delete the old one from middle, but you can't do that either. (you can delete every entry of a specific integer, not a single one)
I read everything there was about std::forward_list on cplusplus.com and googled this for 15 minutes, no results.
Combine these three points to erase a given element (given position) in forward_list :
Use erase_after that remove the one (or range) after the a position.
Use two iterators, prev and it, where prev keep the previous position and it keep the actual position.
Use before_begin to initialize prev and begin to initialize it. This is very important to be able to delete the element at the first position if it matches.
std::forward_list<int> mylist = {10, 10, 20, 30, 40, 10, 50, 10, 60};
int skey = 10;
for (int & val : mylist) std::cout<<val<<", ";
auto prev = mylist.before_begin();
for (auto it = mylist.begin(); it!=mylist.end(); ++it)
{
if(*it==skey) // or if(it== input_it_pos) for a known position
{
mylist.erase_after(prev);
break;
}
prev=it;
}
std::cout<<"\n after deletion : "<<std::endl;
for (int & val : mylist) std::cout<<val<<", ";
Note 1: you can change the code to delete all the elements that match in following manner:
auto prev = mylist.before_begin();
for (auto it = mylist.begin(); it!=mylist.end(); )
{
if(*it==skey)
{
it = mylist.erase_after(prev);
// break; // Comment or uncomment to deal with only the first or all the found element(s).
}
else
{
prev = it;
++it;
}
}
Note 2: if you don't use before_begin, and the two prev and it begins from the same point: (forward_list.begin()) , you can check the first element alone and then use pop_front to delete it.
you can use remove, remove_if to remove all the elements from your forward_list (remove: that compare equal to val, remove_if: which Predicate pred returns true).
Here you are!
// Example program
#include <iostream>
#include <string>
#include <forward_list>
void EraseAtPosition(std::forward_list<int>::iterator pos, std::forward_list<int>& your_list) {
// Find the position before input pos
std::forward_list<int>::iterator prev;
for (auto it = your_list.before_begin(); it != your_list.end();) {
prev = it;
if (++it == pos) {
break;
}
}
// Erase out of list
your_list.erase_after(prev);
}
int main()
{
std::forward_list<int> l = {1, 2, 3, 5};
std::forward_list<int>::iterator target = l.begin();
EraseAtPosition(target, l);
for (auto it = l.begin(); it != l.end(); ++it) {
std::cout << *it << "\n";
}
return 0;
}
You can use Dobly Link list. ( i hope simple link list can also do your task)
Here is the link for doubly link list. https://www.hackerearth.com/practice/notes/doubly-linked-list-data-structure-in-c/
Follow these steps:
1. Copy middle element.
2. add that copied element to the start of list.
3. remove the middle element.
If you are using some library of list that is restricting you, make your own class of list of which removal from any index is possible.
I have a vector, words_in_family, of type: vector<vector<string>>. I am trying to delete every element of words_in_family that is not equal to the string vector largest_family, but am having issues and am unsure of why. Any help is appreciated.
for (int i = words_in_family.size() - 1; i >= 0; i--)
{
if (words_in_family[i] != largest_family)
{
words_in_family.erase(words_in_family[i]);
}
}
erase method doesn't take value. Instead use iterator as parameter for erase method:
vector<vector<string>>::iterator it = words_in_family.begin();
for (int i = words_in_family.size() - 1; i >= 0; i--)
{
if (words_in_family[i] != largest_family)
{
words_in_family.erase(it+i);
}
}
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
Note that the iterators for std::vector are random access iterators so you can add/subtract integral values to get other valid iterators.
C++ std::vector erase an element, in your case:
Erase an element from a vector(words_in_family) whose value is equal to largest_family:
std::vector<std::vector<std::string>>::iterator Itr;
for(Itr = Words_in_family.begin(); Itr != Words_in_family.end();)
{
if(*Itr == largest_family)
{
Itr = Words_in_family.erase(Itr);
}
else
{
Itr++;
}
}
words_in_family.erase(words_in_family.begin()+i, words_in_family.begin()+i+1);
erase takes iterator as an argument
Given a map, I need to retrieve and operate two immediately stored items.
To me, working on a vector is litter easier since I can do "iter + 1" or "iter - 1".
While for map, I am out of luck.
For example, I give a simple example as follows:
Note: in my real application, I don't simply subtract those numbers.
int main ()
{
map<char,int> mymap;
map<char,int>::iterator it;
mymap['b'] = 100;
mymap['a'] = 200;
mymap['c'] = 300;
// show content:
map<char,int>::iterator firstItem = mymap.begin();
map<char,int>::iterator secondItem = ++mymap.begin();
for ( ; secondItem != mymap.end(); ++firstItem, ++secondItem )
cout << secondItem->second - firstItem->second << endl;
return 0;
}
Question> Is there a better solution for this?
Thank you
Instead of incrementing both iterators in the loop control (incrementing is a bit slow), just assign firstItem = secondItem then increment secondItem.
You can do it with a single iterator. Move the increment from the header to the middle of your loop, and exit the loop when you hit the end of your map, like this:
map<char,int>::iterator item = mymap.begin();
for (;;) {
int first = item->second;
++item;
if ( item == mymap.end()) break;
cout << item->second - first << endl;
}
This is a matter of style. You can do eg.
auto first = m.begin();
if (first != m.end())
{
auto second = first;
second++;
for (; second != m.end(); first = second++)
{
...
}
}
You can also bailout more elegantly in the case where the map is empty. For instance you can do:
if (m.empty()) return;
auto first = m.begin(), second = first;
for (second++; second != m.end(); first = second++)
{
...
}
I'd favor the latter if I can, and use the former only if I must.
Your current loop will show undefined behaviour if the map is empty.
Your loop could be rewritten (more simply, and checking for an empty map) like so:
int main(int argc, char * argv[])
{
map<char,int> mymap;
map<char,int>::iterator it;
mymap['b'] = 100;
mymap['a'] = 200;
mymap['c'] = 300;
for ( it = ( mymap.begin() == mymap.end() ? mymap.end() : std::next(mymap.begin()) ) ; it != mymap.end(); ++it )
cout << it->second - std::prev(it)->second << endl;
return 0;
}
Your code will have undefined behavior if the map is empty but other than that it seems to be a reasonable approach, depending on your overall goal. Since map iterators are not random access you can't just add or subtract one, only increment/decrement.
An alternate approach is to make a copy of the iterator and then incrementing inside the loop.
Neither better, nor worse, just an alternative:
if (map.size() >=2)
std::accumulate(
++mymap.begin(),
mymap.end(),
mymap.begin(),
[](mymap_type::const_iterator iprev, mymap_type::value_type const& entry)->mymap_type::const_iterator
{
/* do something */;
return ++iprev;
});
#include<iostream>
#include<list>
using namespace std;
void compute(int num)
{
list<int> L;
list<int>::iterator i;
list<int>::iterator i2;
int p;
cout<<"Enter the number of numbers\n";
cin>>p;
int a;
for(int k=1;k<=p;k++)
{
cin>>a;
L.push_back(k);
}
cout<<endl;
for(i=L.begin() ; i!=L.end() ; ++i)
{
cout<<*i<<endl;
}
long int k=1;
for(i=L.begin() ; i!=L.end() ; ++i )
{
if(k%2!=0) //This is where I try and delete values in odd positions
{
i2=L.erase(i);
}
k++;
}
for(i=L.begin() ; i!=L.end() ; ++i )
{
cout<<*i<<endl;
}
}
int main()
{
// int testcases, sailors;
//cin>>testcases;
//for(int i=1 ; i<=testcases ; i++)
{
// cin>>sailors;
}
//for(int i=1;i<=testcases;i++)
{
// int num;
//cin>>num;
//compute(num);
}
compute(0);
return 0;
}
I am trying to erase elements using L.erase() function in Lists. But I get an error saying
"Debug assertion failed! ......Expression:list iterator not incrementable"
but we CAN increment iterator right?
erase invalidates the iterator that was passed in as parameter - since the element at the position the iterator was pointing to was just erased! And on that same iterator, an increment is attempted in the next for loop in your code! That's why it fails.
However, erase it will return an iterator pointing to the new position, which we can use; a loop where you erase something from an STL container should therefore look something like the following; I show it with the type you use, list, but you could just as well use e.g. vector:
list<int> L;
// ...
list<int>::iterator it=L.begin();
while (it!=L.end())
{
if(eraseCondition)
{
it=L.erase(it);
}
else
{
++it;
}
}
Or, if possible, it's even better to use std::remove_if:
container.erase(std::remove_if(L.begin(), L.end(), predicate), L.end());
In your case that will be hard - if not impossible - to use since the predicate would need state information (the information whether the index is odd or even). So I'd recommend going with a loop structure as mentioned above; just keep in mind the remove_if for the general case of removing all elements where a certain predicate returns true!
Adding to what wOOte said, you may want to used a reverse iterator to get around the issue.
Technically not in this case.
When you use erase() you delete the node that was pointed to, so you actually invalidate the iterator you were on. So when you increment it it's undefined behavior.
It might be best to create a second list with just the iterators to the positions you'd like to delete, and you can cycle through those and call erase afterward. You wouldn't be erasing the iterators from the second list, so it'd work.
Something like this:
List<IteratorType> deleteList;
//Populate deleteList with every other element from original list.
for (List<IteratorType>::iterator iter = deleteList.begin();
iter !=deleteList.end; ++iter)
{
originalList.erase(*iter);
}
The iterator i is invalidated by the call to erase; however, in the next iteration of the for loop, you try to increment it - this is invalid.
Try
for(i=L.begin() ; i!=L.end() ; )
{
if(k%2!=0) //This is where I try and delete values in odd positions
{
i=L.erase(i);
} else {
++i;
}
k++;
}
instead - only increment the iterator if you don't erase (erase basically "advances" the iterator because it yields an iterator to the element following the one you erased).
You can actually exploit this behaviour of erase to write your function without requiring k:
i = L.begin();
while ( i != L.end() ) {
i = L.erase( i ); // Delete one
if ( i != L.end() ) { // Skip next, if there's an element
++i;
}
}
So you delete the first element, skip the second, delete the third, and so on.
I've got code that looks like this:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
I'd like remove inactive items immediately after update them, inorder to avoid walking the list again. But if I add the commented-out lines, I get an error when I get to i++: "List iterator not incrementable". I tried some alternates which didn't increment in the for statement, but I couldn't get anything to work.
What's the best way to remove items as you are walking a std::list?
You have to increment the iterator first (with i++) and then remove the previous element (e.g., by using the returned value from i++). You can change the code to a while loop like so:
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i++); // alternatively, i = items.erase(i);
}
else
{
other_code_involving(*i);
++i;
}
}
You want to do:
i= items.erase(i);
That will correctly update the iterator to point to the location after the iterator you removed.
You need to do the combination of Kristo's answer and MSN's:
// Note: Using the pre-increment operator is preferred for iterators because
// there can be a performance gain.
//
// Note: As long as you are iterating from beginning to end, without inserting
// along the way you can safely save end once; otherwise get it at the
// top of each loop.
std::list< item * >::iterator iter = items.begin();
std::list< item * >::iterator end = items.end();
while (iter != end)
{
item * pItem = *iter;
if (pItem->update() == true)
{
other_code_involving(pItem);
++iter;
}
else
{
// BTW, who is deleting pItem, a.k.a. (*iter)?
iter = items.erase(iter);
}
}
Of course, the most efficient and SuperCool® STL savy thing would be something like this:
// This implementation of update executes other_code_involving(Item *) if
// this instance needs updating.
//
// This method returns true if this still needs future updates.
//
bool Item::update(void)
{
if (m_needsUpdates == true)
{
m_needsUpdates = other_code_involving(this);
}
return (m_needsUpdates);
}
// This call does everything the previous loop did!!! (Including the fact
// that it isn't deleting the items that are erased!)
items.remove_if(std::not1(std::mem_fun(&Item::update)));
I have sumup it, here is the three method with example:
1. using while loop
list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
2. using remove_if member funtion in list:
list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
3. using std::remove_if funtion combining with erase member function:
list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
4. using for loop , should note update the iterator:
list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Use std::remove_if algorithm.
Edit:
Work with collections should be like:
prepare collection.
process collection.
Life will be easier if you won't mix this steps.
std::remove_if. or list::remove_if ( if you know that you work with list and not with the TCollection )
std::for_each
The alternative for loop version to Kristo's answer.
You lose some efficiency, you go backwards and then forward again when deleting but in exchange for the extra iterator increment you can have the iterator declared in the loop scope and the code looking a bit cleaner. What to choose depends on priorities of the moment.
The answer was totally out of time, I know...
typedef std::list<item*>::iterator item_iterator;
for(item_iterator i = items.begin(); i != items.end(); ++i)
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i--);
}
else
{
other_code_involving(*i);
}
}
Here's an example using a for loop that iterates the list and increments or revalidates the iterator in the event of an item being removed during traversal of the list.
for(auto i = items.begin(); i != items.end();)
{
if(bool isActive = (*i)->update())
{
other_code_involving(*i);
++i;
}
else
{
i = items.erase(i);
}
}
items.remove_if(CheckItemNotActive);
Removal invalidates only the iterators that point to the elements that are removed.
So in this case after removing *i , i is invalidated and you cannot do increment on it.
What you can do is first save the iterator of element that is to be removed , then increment the iterator and then remove the saved one.
If you think of the std::list like a queue, then you can dequeue and enqueue all the items that you want to keep, but only dequeue (and not enqueue) the item you want to remove. Here's an example where I want to remove 5 from a list containing the numbers 1-10...
std::list<int> myList;
int size = myList.size(); // The size needs to be saved to iterate through the whole thing
for (int i = 0; i < size; ++i)
{
int val = myList.back()
myList.pop_back() // dequeue
if (val != 5)
{
myList.push_front(val) // enqueue if not 5
}
}
myList will now only have numbers 1-4 and 6-10.
Iterating backwards avoids the effect of erasing an element on the remaining elements to be traversed:
typedef list<item*> list_t;
for ( list_t::iterator it = items.end() ; it != items.begin() ; ) {
--it;
bool remove = <determine whether to remove>
if ( remove ) {
items.erase( it );
}
}
PS: see this, e.g., regarding backward iteration.
PS2: I did not thoroughly tested if it handles well erasing elements at the ends.
You can write
std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
bool isActive = (*i)->update();
if (!isActive) {
i = items.erase(i);
} else {
other_code_involving(*i);
i++;
}
}
You can write equivalent code with std::list::remove_if, which is less verbose and more explicit
items.remove_if([] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
});
The std::vector::erase std::remove_if idiom should be used when items is a vector instead of a list to keep compexity at O(n) - or in case you write generic code and items might be a container with no effective way to erase single items (like a vector)
items.erase(std::remove_if(begin(items), end(items), [] (item*i) {
bool isActive = (*i)->update();
if (!isActive)
return true;
other_code_involving(*i);
return false;
}));
do while loop, it's flexable and fast and easy to read and write.
auto textRegion = m_pdfTextRegions.begin();
while(textRegion != m_pdfTextRegions.end())
{
if ((*textRegion)->glyphs.empty())
{
m_pdfTextRegions.erase(textRegion);
textRegion = m_pdfTextRegions.begin();
}
else
textRegion++;
}
I'd like to share my method. This method also allows the insertion of the element to the back of the list during iteration
#include <iostream>
#include <list>
int main(int argc, char **argv) {
std::list<int> d;
for (int i = 0; i < 12; ++i) {
d.push_back(i);
}
auto it = d.begin();
int nelem = d.size(); // number of current elements
for (int ielem = 0; ielem < nelem; ++ielem) {
auto &i = *it;
if (i % 2 == 0) {
it = d.erase(it);
} else {
if (i % 3 == 0) {
d.push_back(3*i);
}
++it;
}
}
for (auto i : d) {
std::cout << i << ", ";
}
std::cout << std::endl;
// result should be: 1, 3, 5, 7, 9, 11, 9, 27,
return 0;
}
I think you have a bug there, I code this way:
for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin();
itAudioChannel != audioChannels.end(); )
{
CAudioChannel *audioChannel = *itAudioChannel;
std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel;
itAudioChannel++;
if (audioChannel->destroyMe)
{
audioChannels.erase(itCurrentAudioChannel);
delete audioChannel;
continue;
}
audioChannel->Mix(outBuffer, numSamples);
}