проблема с обновлением карты путем удаления некоторых ключей, а также некоторых элементов - PullRequest
0 голосов
/ 15 сентября 2011

У меня есть карта.скажем map<int, vector<int> > mymap1.Я хочу обновить mymap1, удалив некоторые «ключи», а также удалив ненужные «элементы» из векторной части выбранных ключей.«Ключ» или «элемент», который будет удален, дан из другого вектора, известного как «mylabel».На самом деле, то, что мне нужно, чтобы остаться в моей карте, это значения, метка которых равна 1. (В конце ключи должны иметь элементы, метка которых равна только 1).

Я реализовал это (см. Кодниже), но получил некоторые ошибки компилятора.

map<int, vector<int> > mymap1;
map<int, vector<int> >::iterator map1;
for (map1=mymap1.begin();map1!=mymap1.end();map1++){
       int key = map1->first;
       if (mylabel[key].Label() != 1){ mymap1.erase(key);
       }

       else{
            vector<int> &myvec = map1->second;
            for (vector<int>::iterator rn=myvec.begin(); rn!=myvec.end(); rn++){
                 if (mylabel[*rn].Label() != 1) myvec.erase(myvec.begin()+(*rn));
            }                        
       }
}

, чтобы вы могли получить представление, я показываю какой-то пример моей карты.

0 1 2 6 10
1 0 2 4 3 6
2 0 1 3 5 8
3 1 2 4 5 7
4 1 3 6 7
5 2 3 8 7 9
6 1 0 7 4
7 6 4 3 5 9 11 10 13 12
8 2 5 9 11 18 15 19 20 22
9 5 7 11 8
10 0 7 14 16
11 9 7 8 13
12 7 13 14
13 7 12 11 14 15
14 12 10 16 13 15 17
15 13 14 8 17 19
16 14 10 17 21
17 14 16 15 21 18
18 8 20 19 17 26 27
19 8 15 18
20 8 18
21 16 17 23 24
22 8
23 25 21 24 26
24 23 21
25 23 26
26 23 25 18
27 18 28
28 27

, если я покажу вам мой mylabel,это выглядит следующим образом.

for(int c=0;c<mylabel.size();c++){
    cout<<c<<" : "<<"label "<<mylabel[c].Label()<<endl;
}
0 : label 0
1 : label 0
2 : label 0
3 : label 0
4 : label 0
5 : label 1
6 : label 0
7 : label 1
8 : label 0
9 : label 1
10 : label 0
11 : label 1
12 : label 0
13 : label 0
14 : label 1
15 : label 1
16 : label 1
17 : label 1
18 : label 0
19 : label 0
20 : label 0
21 : label 1
22 : label 0
23 : label 0
24 : label 0
25 : label 1
26 : label 1
27 : label 0
28 : label 0

Когда я деактивирую остальную часть и работаю над кодом, я получаю вывод.Но я хочу сказать вам, что это неправильный результат.Я получаю дополнительные ключи, которые должны быть удалены.Я не могу понять, почему я получил этот результат ошибки.если я покажу список ключей, которые я получил,

5
7
9
11
14
15
16
17
20 - wrong
21
24 - wrong
25
26

не могли бы вы помочь мне исправить мой код, чтобы получить мою измененную карту.заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 15 сентября 2011

Ваша логика удаления неверна, и вы в конечном итоге используете недопустимые итераторы.(Вы буквально вытаскиваете коврик из-под ног, если вы стираете итератор, а затем продолжаете использовать этот итератор.)

Для контейнеров на основе узлов (список, карта, набор, неупорядоченный) вы обычно стираетеследующим образом:

for (auto it = c.begin(); it != c.end(); )
{
  if (must_delete(*it))  // or it->first
  {
    c.erase(it++); // advance first, then erase previous
  }
  else
  {
    ++it;
  }
}

(Этот шаблон - мое любимое оправдание для оператора приращения после исправления.)

Для смежных контейнеров (vector, deque) стирание по одному элементу за разнеэффективно, потому что это влечет за собой повторные ходы.Предпочтительная идиома здесь - «удалить / стереть», но она требует, чтобы вы указали подходящий предикат, если вы не хотите просто удалять значение по элементу.Вот пример с лямбдами, для краткости:

std::vector<int> v;
v.erase(std::remove_if(v.begin(), v.end(),
                       [](int n)->bool{return some_criterion(n);}),
        v.end());

В вашей ситуации вы можете написать лямбду как [mylabel&](n)->bool{ return mylabel[n].Label() != 1; };или напишите традиционный объект предиката, если у вас нет лямбда-выражений:

struct LabelFinder
{
  LabelFinder(const LabelVector & lv) : label(lv) { }

  inline bool operator()(int n) const
  {
    return label[n].Label() != 1;
  }

private:
  const LabelVector & label;
};

Теперь используйте:

v.erase(std::remove_if(v.begin(), v.end(), LabelFinder(mylabel)), v.end());
1 голос
/ 15 сентября 2011

Проблема в цикле for.std::vector<T>::erase() возвращает итератор на новую позицию, за которым следует стертый элемент.Таким образом, цикл должен быть записан как:

for (vector<int>::iterator rn=myvec.begin(); rn!=myvec.end();)
{
       if (mylabel[*rn].Label() != 1) 
             rn = myvec.erase(rn);
       else
             ++rn;
}   

Прочитайте документ:

Кстати, я сомневаюсь в этом:

 rn = myvec.erase(myvec.begin()+(*rn));
            Vs
 rn = myvec.erase(rn);

Вы уверены, что хотите первый?


Идиоматический способ стереть элементы, которые не равны одному, этоэто:

 //Define this function
 bool isNotOne(int n) {  return n != 1; }

//then do this instead of writing manual loop
 myvec.erase( remove_if(myvec.begin(), myvec.end(), isNotOne), myvec.end() ); 

Это называется:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...