1
votes

Fractionner le vecteur en plusieurs tableaux / vecteurs C ++

J'ai un problème pour diviser un vecteur chaîne en un vecteur entier plus petit \ array. Mes données vectorielles d'entrée ressemblent à:

std::vector<std::string> v(2);
v[0] = "0 14 150";
v[1] = "1 2 220";
//...

Je connais une solution, faire trois tableaux et utiliser sstream pour convertir des données en entier. Mais je veux éviter de créer du code "spaghetti".

Merci, Peter.


6 commentaires

Voulez-vous transformer std :: vector dans std::vector> ?


Veuillez poster au moins un code réel et non imaginaire qui ne serait même pas compilé. Mais mieux vaut fournir un exemple reproductible minimal


Votre code ne se compilera pas. Vouliez-vous dire v [0] = "0 14 150"; ? Et veuillez préciser quel (s) type (s) de conteneur (s) souhaitez-vous obtenir?


vector contient un type de données chaîne. Je veux le convertir en 3 tableaux / vecteurs plus petits. Plonger la longueur du vevtor de moitié ne me sauve pas.


Vos 3 tableaux / vecteurs plus petits signifient-ils {0,1} , {14,2} et {150,220} ?


Hiroki, non peut-être que je l'ai mal écrit. Les résultats attendus sont: trois tableaux arr1 [0] = 0, arr2 [0] = 14; arr3 [0] = 150, c'est tout.


3 Réponses :


1
votes

J'ai trouvé une fonction de fractionnement sur stackoverflow il y a quelque temps. Malheureusement, je ne peux plus poster le lien.

#include <string>
#include <vector>

class BasicVariant
{
private:
    std::string str;
public:
    BasicVariant(const std::string& _str) :str(_str) {}
    BasicVariant(int value) :str(std::to_string(value)) {}
    BasicVariant(double value) :str(std::to_string(value)) {}
    inline int toInt()const { return *this; }
    inline double toDouble()const { return *this; }
    inline std::string toString()const { return *this; }
    inline bool toBool()const { return toDouble(); }
    inline operator int()const { return std::stoi(str); }
    inline operator double()const { return std::stof(str); }
    inline operator std::string()const { return str; }
    inline operator bool()const { return toDouble(); }
};


template<typename T>
void split(const std::string& str, std::vector<T>& sink, const std::string& delims)
{
    std::size_t current, previous = 0;
    current = str.find_first_of(delims);
    while (current != std::string::npos)
    {
        sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
        previous = current + 1;
        current = str.find_first_of(delims, previous);
    }
    sink.push_back(std::move(BasicVariant(str.substr(previous, current - previous))));
}




int main()
{
    std::vector<std::string> vec{ "0 14 150","1 2 220" };
    std::vector<std::vector<int>> intVec(3, std::vector<int>(vec.size()));
    for (int i = 0; i < vec.size(); i++)
    {
        std::vector<int> row;
        split(vec[i], row, " ");
        for (int j = 0; j < row.size(); j++)
            intVec[j][i] = row[j];
    }

    system("pause");
}

J'aurai besoin d'un délimiteur dans vos chaînes (semble être un retour arrière dans votre cas) et appeler la fonction sur chaque élément de votre vecteur de chaîne: p>

int main()
{
std::vector<std::string> vec{ "0 14 150","1 2 220" };
std::vector<std::vector<int>> intVec(3,std::vector<int>(vec.size()));
for (int i = 0; i < vec.size(); i++)
{
    std::vector<std::string> singleStr;
    split(vec[i], singleStr, " ");
    for (int j=0; j < singleStr.size();j++)
        intVec[j][i] = (std::stoi(singleStr[j]));
}

system("pause");
}

Une solution plus générique pourrait ressembler à ceci. Vous pouvez ajouter d'autres types à BasicVariant

void split(const std::string & str, std::vector<std::string>& cont, const std::string & delims)
{
    std::size_t current, previous = 0;
    current = str.find_first_of(delims);
    while (current != std::string::npos) 
    {
        cont.push_back(std::move(str.substr(previous, current - previous)));
        previous = current + 1;
        current = str.find_first_of(delims, previous);
    }
    cont.push_back(std::move(str.substr(previous, current - previous)));
}


11 commentaires

ça a l'air bien, mais les «lignes» dans mon vecteur de chaîne contiennent 3 variables int différentes.


Hm ... je l'ai essayé et une seule ligne contient trois variables et l'ensemble intVec devrait contenir 2 éléments


Désolé, je vous ai mal compris. J'ai mis à jour ma fonction principale. intVec contient 3 éléments {0,1}, {14,2} et {150,220}


Il est plus proche de résoudre mon problème, merci. Le résultat attendu doit être: from vector vec [x] -> int array1 [x] ou int vec1 [x], int array2 [x] ou int vec2 [x], int array3 ou int vec3 [x]. La sortie doit être comme: array1 [0] = 0, array2 [0] = 14, array3 [0] = 150 @StephanH pourriez-vous nous aider? Je devrais peut-être mettre plus de données ici pour expliquer mon problème.


Bien sûr. Pouvez-vous publier la sortie après la deuxième chaîne de votre vecteur? Est-ce: array1 [0] = 1, array2 [0] = 2, array3 [0] = 220 Si oui, comment voulez-vous stocker les vecteurs de la première chaîne calculée?


@PPeter Je pense que nous avons déjà obtenu le résultat essentiellement le même.


Hiroki et ma solution produisent cette sortie.


@Hiroki belle solution, devrait être beaucoup plus rapide que la mienne


Ok hf :) si vous insistez sur les tableaux indépendants, vous pouvez ajouter quelque chose comme std :: vector arr0 (make_move_iterator (intVec [0] .begin ()), make_move_iterator (intVec [0] .end ()));


@StephanH Hmm .. le processus de transposition dans ma solution peut être assez verbeux.


@StephanH merci beaucoup 2 :) :) Je ne peux pas joindre plus d'une personne par commentaire



0
votes

Modifier: J'ai supprimé une fonction de transposition détaillée.


Je suppose que vous voulez convertir std::vector<:string> en une matrice 2D std::vector<:vector>> . Par exemple, pour votre exemple, le résultat souhaité est supposé être arr1 = {0,1, ...} , arr2 = {14,2, ...} code > et arr3 = {150,220, ...} .

Premièrement,

  • Nous pouvons utiliser std :: istream_iterator pour extraire les entiers des chaînes.

  • Nous pouvons également appliquer le constructeur de plage pour créer un std::vector correspondant à chaque chaîne.

Donc, la fonction suivante fonctionnerait pour vous et cela ne me semble pas du moins être un code spaghetti . Tout d'abord, cette fonction extrait deux tableaux d'entiers {0,14,150, ...} et {1,2,220, ...} sous forme de matrices à partir d'un vecteur de chaîne passé v . Comme un std :: istream_iterator construit par défaut est un itérateur de fin de flux, chaque constructeur de plage lit chaque chaîne jusqu'à ce qu'il ne parvienne pas à lire la valeur suivante. Et enfin, une transposée est renvoyée:

std::vector<std::string> v(n);
v[0] = "0 14 150";
v[1] = "1 2 220";
...
v[n-1] = "...";

auto matrix = extractNumbers<int>(v);

Ensuite, vous pouvez extraire des entiers d'un vecteur chaîne comme suit:

DEMO

#include <vector>
#include <string>
#include <sstream>
#include <iterator>

template <typename T>
auto extractNumbers(const std::vector<std::string>& v)
{
    std::vector<std::vector<T>> extracted;
    extracted.reserve(v.size());

    for(auto& s : v)
    {
        std::stringstream ss(s);
        std::istream_iterator<T> begin(ss), end; //defaulted end-of-stream iterator.

        extracted.emplace_back(begin, end);
    }

    // this also validates following access to extracted[0].
    if(extracted.empty()){
        return extracted;
    }

    decltype(extracted) transposed(extracted[0].size());
    for(std::size_t i=0; i<transposed.size(); ++i){
        for(std::size_t j=0; j<extracted.size(); ++j){
            transposed.at(i).push_back(std::move(extracted.at(j).at(i)));
        }
    }

    return transposed;
}

matrice [0] est arr1 , matrice [1] est arr2 , et ainsi de suite. Nous pouvons également en obtenir rapidement des pointeurs internes par auto arr1 = std :: move (matrix [0]); .


0 commentaires

0
votes

Nous avons ici quelques malentendus.
La sortie de mon programme doit avoir trois tableaux / vecteurs.

La sortie ressemble à:

arr1| arr1| arr3
0   | 14  | 150
1   |  2  | 220
2   |  4  | 130  


0 commentaires