Vector i problem z ladnym usunieciem oraz wpisaniem

0

owoce to vector zapelniony nazwami i ta petla poprawnie usuwa wszystkie elementy zaczynajace na 'a', ale jak pozbyc sie tego licznika, by zostal sam iterator ?

 int i = 0;
 for (i = 0, s = owoce.begin(); i < owoce.size(); i++, s++)  
        if (owoce[i][0] == 'a' || owoce[i][0] == 'A')  //jak tu zrobic by moc pozbyc sie tego 'i' z calej petli
            owoce.erase(s);
 

jak zrobic by wczytywanie konczylo sie podaniem pustej lini i potwierdzeniem klawisza enter (bez tej zmiennej pomocniczej q)

  std::string t;
    while (std::cin >> t && t != "q")
    {
        owoce.push_back(t);
    } 

z gory dzieki, pozdro

0

Poprawnie to Ci na pewno nie działa. Po pierwszym skasowanym owocu na 'A' wszystko Ci się rozjedzie.
Najłatwiej zrobić to za pomocą listy a nie vectora - no chyba, że tak musi być bo coś tam. Więc jeśli to już musi być vector, to ja bym zrobił to podobnie jak Ty, z tą różnicą, że pętla iterowałaby od końca.

for(int i = (int)owoce.size(); i >= 0; i--){

    if((owoce[i][0] == 'a') || (owoce[i][0] == 'A')){

        owoce.erase(owoce.begin() + i);
    }
}
0
  1. Po usunięciu elementu iterator TRACI WAŻNOŚĆ, niezależnie od kontenera, lista wektor nie robi różnicy (są tylko inne skutki uboczne).
  2. Najlepiej stosować algorytmy stl-a.

To powinno wyglądać tak (trochę rozwlekle, ale bardziej uniwersalnie):

class StartsWithLetter {
public:
      StartsWithLetter(char letter, bool caseInsensitive = false) :
            mLetter(caseInsensitive?tolower(letter):letter),
            mCaseInsensitive(caseInsensitive)
      {
      }

      bool operator(const std::string& s) const 
      {
            if (mCaseInsensitive) {
                return tolower(s[0])==mLetter;
            } else {
                return s[0]==mLetter;
            } 
      }

private:
      char mLetter;
      bool mCaseInsensitive;
};

// wersja krótka
bool hasLetterAAtStart(const std::string& s)
{
     return s[0]=='a' || s[0]=='A';
}

std::remove_if(owoce.begin(), owoce.end(), StartsWithLetter('a', ture));
std::remove_if(owoce.begin(), owoce.end(), hasLetterAAtStart);
0

ok, dzieki, skorzystam z tego uniwersalnego alg

mam jednak 2 pytania:

  1. Po moim zle dzialajacym kodzie, wypisalem sobie ten moj wektor i wszystko zostalo poprawnie wypisane (usunieto elementy zaczynajace na a i reszte wypisano), dlaczego program sie nie posypal ?

  2. Marek, co to znaczy "iterator traci waznosc" ? (to, ze nie można w tej petli go już uzywac, bo pokazuje na jakies smieci? a w kolejnej od nowa petli chyba już można ?)

0
for(int i = (int)owoce.size() -1; i >= 0; i--){     // ten kod z drobna zmiana dziala ok :)

    if((owoce[i][0] == 'a') || (owoce[i][0] == 'A')){

        owoce.erase(owoce.begin() + i);
    }
} 
bool hasLetterAAtStart(const std::string& s) {      return s[0]=='a' || s[0]=='A'; } 
 std::remove_if(owoce.begin(), owoce.end(), hasLetterAAtStart); 

ten uniwerslany alg z stl'a usuwa tylko pierwszy wyraz na 'a', wiec cos jest nie tak, a ja tego kompletnie nie rozumie :D

0
std::vector<string>::iterator it = std::remove_if(owoce.begin(), owoce.end(), hasLetterAAtStart);
owoce.erase(it,owoce.end());
0

ok, dzieki, dziala ok :)
tylko jakim cudem, jak to sie tak fizycznie dzieje ?
na moj rozum, pierwsza linijka znajduje pierwszy wyraz na a i na niego pokazuje iterator
pozniej jest usuwany ten element i ewentualnie identyczne elementy z tym znalezionym

i jakim cudem teraz program wyszukuje kolejny element na 'a' ?

0

Tu nie chodzi o wyszukiwanie, bo to ta funkcja robiła, tylko o to, że nie skarałeś zbioru, przez co na końcu zalegały stare elementy. Dla przykładu, dla tablicy:

a,b,c,a,d,a,f

remove_if zwróci:

b,c,d,f,d,a,f

d to jest miejsce, na które wskazuje zwrócony przez funkcję iterator, jest to koniec "nowego" zbioru. Jak łatwo się domyślić, trzy ostatnie elementy należy usunąć, i robi linijka z erase.

1 użytkowników online, w tym zalogowanych: 0, gości: 1