2
votes

Comment remplacer une séquence en vecteur

Supposons que j'ai le vecteur suivant:

std::vector<int> data{0,1,2,3,4};

Je voudrais remplacer la séquence {1,2,3} par un seul nombre. J'ai trouvé un exemple avec std :: replace mais là, un seul numéro est remplacé par un autre numéro unique. Comment remplacer une séquence en vecteur?


1 commentaires

Supprimez deux des trois valeurs. Remplacez ensuite l'existant.


5 Réponses :


0
votes

Premièrement: vector :: effacer

// inserting into a vector
#include <iostream>
#include <vector>

int main ()
{
std::vector<int> myvector (3,100);
std::vector<int>::iterator it;

it = myvector.begin();
it = myvector.insert ( it , 200 );

myvector.insert (it,2,300);

// "it" no longer valid, get a new one:
it = myvector.begin();

std::vector<int> anothervector (2,400);
myvector.insert (it+2,anothervector.begin(),anothervector.end());

int myarray [] = { 501,502,503 };
myvector.insert (myvector.begin(), myarray, myarray+3);

std::cout << "myvector contains:";
for (it=myvector.begin(); it<myvector.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';

return 0;
}

Production: myvector contient: 4 5 7 8 9 10

Ensuite: vector :: insert

// erasing from vector
#include <iostream>
#include <vector>

int main ()
{
std::vector<int> myvector;

// set some values (from 1 to 10)
for (int i=1; i<=10; i++) myvector.push_back(i);

// erase the 6th element
myvector.erase (myvector.begin()+5);

// erase the first 3 elements:
myvector.erase (myvector.begin(),myvector.begin()+3);

std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';

return 0;
}


0 commentaires

0
votes

Vous pouvez peut-être écrire une fonction personnalisée, comme celle-ci:

    vector<int> replace_sequence(const vector<int> in,int start,int end,int replace)
    {
        vector<int> res;
        //check the index value
        if(start<0 || end > in.size() || start > end){
            return res;
        }
        int distance = end -start;
        //construct the result
        for(int i=0;i<in.size();i++){
            if(i==start){
                res.push_back(replace);
                i+=distance;
            }else{
                res.push_back(in[i]);
            }
        }
        return res;
    }


0 commentaires

0
votes
bool erase_replace_seq (vector <int>& data, int start, int end, int replace)
{
    bool result = false;
if ((start<data.size () && start>=0)  && (end < data.size () && end >=0 && end >= start))
    {
        auto iter = data.erase (data.begin () + start, data.begin () + end);
        data.insert (iter, replace);
        result = true;
    }

    return result;
}

0 commentaires

1
votes

Nous pouvons le faire en utilisant std :: vector :: erase (const_iterator en premier, const_iterator en dernier) comme suit. La fonction suivante remplace la valeur de org [start] par val puis efface les éléments de la plage [start + 1, end] :

DÉMO

template<class T>
std::vector<T> replace(
    const std::vector<T>& org, 
    std::size_t start, 
    std::size_t end, 
    const T& val)
{
    assert(start <= end);
    assert(end < org.size());

    auto vec(org);
    auto it_s = vec.begin() + start;
    *it_s = val;

    vec.erase(it_s + 1, vec.begin() + end + 1);

    return vec;    
}


0 commentaires

1
votes

J'ai généralisé votre question dans n'importe quel conteneur STL en utilisant des paires d'itérateurs au lieu de vecteurs pour l'entrée. L'algorithme comporte 3 étapes:

  1. Recherchez la séquence via std :: search . Renvoie le dernier s'il n'est pas trouvé
  2. Remplacer le premier élément de séquence par une nouvelle valeur
  3. Supprimez les éléments restants avec std :: remove_if

Comme les itérateurs ne peuvent pas vraiment effacer les éléments du conteneur, data.erase (newEnd, data.end ()); est nécessaire pour réduire le vecteur.

L'algorithme doit être assez stable et fonctionner même pour les vecteurs à 1 élément. La fonction peut être déclarée constexpr depuis C ++ 14.

int main() {
  std::vector<int> data{0, 1, 2, 3, 4};
  replaceSequenceWithValue(data, {1, 2, 3}, 5);
  for (auto d : data) {
    std::cout << d << '\n';
  }
}

Si vous n'avez pas besoin d'une telle généralisation, vous pouvez l'envelopper en fonction avec une signature plus simple :

template <class Value>
constexpr void replaceSequenceWithValue(std::vector<Value> &data, const std::vector<Value> &sequence, Value &&value) {
  auto newEnd = replaceSequenceWithValue(data.begin(), data.end(), sequence.begin(),
                                         sequence.end(), std::forward<Value>(value));
  data.erase(newEnd, data.end());
}

Et utilisez comme:

#include <algorithm>
#include <iostream>
#include <vector>

template <class ForwardIt1, class ForwardIt2, class Value>
constexpr ForwardIt1 replaceSequenceWithValue(ForwardIt1 first, ForwardIt1 last, 
                                              ForwardIt2 s_first, ForwardIt2 s_last,
                                              Value &&value) {
  auto seq_start = std::search(first, last, s_first, s_last);
  if (seq_start == last)
    return last; // return last if no seq was found

  *seq_start = std::forward<Value>(value);

  auto itemsToBeRemoved = std::distance(s_first, s_last) - 1;

  // return new end
  if (itemsToBeRemoved > 0)
    return std::remove_if(std::next(seq_start), last,
                          [&itemsToBeRemoved](const auto &) { return itemsToBeRemoved-- > 0; });
  return last;
}


int main() {
  std::vector<int> data{0, 1, 2, 3, 4};
  std::vector<int> seq{1, 2, 3};
  auto newEnd = replaceSequenceWithValue(data.begin(), data.end(), seq.begin(), seq.end(), 5);
  data.erase(newEnd, data.end());
  for (auto d : data) {
    std::cout << d << '\n';
  }
}


1 commentaires

Je ne suis pas convaincu de std :: remove_if ici, mais je ne pourrais rien trouver de mieux. std :: rotate peut fonctionner, mais il déplacerait des éléments juste pour être rejetés à la fin du vecteur data . std :: shift_left de C ++ 20 serait parfait à utiliser ici.