Сравнения на низове с c++

Преди имах някакъв код в C++, който съхранява низове като поредица от знаци в символна матрица (низът е ред). Класовете Character matrix и LogicalVector се предоставят от Rcpp.h:

LogicalVector unq_mat( CharacterMatrix x ){
  int nc = x.ncol() ; // Get the number of columns in the matrix. 
  LogicalVector out(nc); // Make a logical (bool) vector of the same length.
  // For every col in the matrix, assess whether the column contains more than one unique character.
  for( int i=0; i < nc; i++ ) {
    out[i] = unique( x(_,i) ).size() != 1 ;
    }
  return out;
}

Логическият вектор идентифицира кои колони съдържат повече от един уникален знак. След това това се предава обратно на езика R и се използва за манипулиране на матрица. Това е много R начин на мислене за това. Независимо от това, че се интересувам от развитието на мисленето си в C++, бих искал да напиша нещо, което постига горното: Така открива кои символи в n низове не са еднакви, но за предпочитане използва stl класове като std::string. Като концептуален пример са дадени три низа: A = "Hello", B = "Heleo", C = "Hidey". Кодът ще посочи, че позиции/символи 2,3,4,5 не са една стойност, но позиция/знак 1 („H“) е един и същ във всички низове (т.е. има само една уникална стойност). Имам нещо по-долу, което мислех, че работи:

std::vector<int> StringsCompare(std::vector<string>& stringVector) {
    std::vector<int> informative;
    for (int i = 0; i < stringVector[0].size()-1; i++) {
        for (int n = 1; n < stringVector.size()-1; n++) {
            if (stringVector[n][i] != stringVector[n-1][i]) {
                informative.push_back(i);
                break;
            }
        }
    }
    return informative;
}

Трябва да премине през всяка позиция на символ (от 0 до размера на низ-1) с външния цикъл и с вътрешния цикъл, вижте дали знакът в низ n не е същият като знака в низ n-1. В случаите, когато символът е един и същ, например H в моя пример за здравей по-горе, това никога няма да е вярно. За случаите, когато символите в низовете са различни, операторът if за вътрешни цикли ще бъде изпълнен, позицията на знака записана и вътрешният цикъл ще бъде прекъснат. След това получавам вектор, съдържащ индексите на символите в n низа, където знаците не са идентични. Тези две функции обаче ми дават различни отговори. Как иначе мога да прегледам n низа char по char и да проверя, че не всички са идентични?

Благодаря, Бен.


person Ward9250    schedule 10.11.2013    source източник
comment
Дребно, но казвате да преминете през всяка позиция на знак (0 до размер на низ-1), но вашият цикъл върви докато i < stringVecotr[0].size()-1 - с по-малко от, нямате нужда от -1   -  person doctorlove    schedule 10.11.2013
comment
Същото важи и за n < stringVector.size()-1 - пропускате последния запис. Също така обмислете използването на size_t вместо int. Не само, че вашият компилатор ще докладва по-малко предупреждения, това също е правилното нещо, което трябва да направите.   -  person IInspectable    schedule 10.11.2013
comment
Горните две наблюдения плюс резултатът, базиран на 0 от C++ кода, коригират ли разликата между функциите?   -  person Matthew Lundberg    schedule 10.11.2013
comment
Това го прави! Сега отговорите са същите. Благодаря! Ако направите това отговор и аз ще го гласувам и ще приема. Можете ли да обясните малко повече защо size_t е по-добър от int? От четенето виждам, че също е цяло число, но без знак?   -  person Ward9250    schedule 10.11.2013
comment
size_t е правилният размер за индекс на масив и е входният тип за operator[] на std::vector или std::string (int ще бъде преобразуван в size_t за тази операция). Още нещо, вашият подпис на C++ функция трябва да бъде std::vector<int> StringsCompare(const std::vector<std::string>& stringVector). Обърнете внимание на const.   -  person Matthew Lundberg    schedule 10.11.2013
comment
Защо искате/трябва да разбиете низовете във вектори на char? Много по-лесно/естествено е да работите с std::vector<std::string>.   -  person Dirk Eddelbuettel    schedule 11.11.2013


Отговори (1)


Очаквах @doctorlove да даде отговор. Ще въведа един тук, в случай че не го направи.

За да преминете през всички елементи на низ или вектор по индекс, вие искате i от 0 до size()-1. for (int i=0; i<str.size(); i++) спира малко по-малко от размера, т.е. спира на size()-1. Така че премахнете -1.

Второ, C++ масивите са базирани на 0, така че трябва да коригирате (чрез добавяне на 1 към стойността, която е избутана във вектора).

std::vector<int> StringsCompare(std::vector<std::string>& stringVector) {
    std::vector<int> informative;
    for (int i = 0; i < stringVector[0].size(); i++) {
        for (int n = 1; n < stringVector.size(); n++) {
            if (stringVector[n][i] != stringVector[n-1][i]) {
                informative.push_back(i+1);
                break;
            }
        }
    }
    return informative;
}

Няколко неща, които трябва да отбележите относно този код:

  1. Функцията трябва да приема постоянна препратка към вектор, тъй като входният вектор не е модифициран. Тук всъщност не е проблем, но поради различни причини е добра идея да декларирате непроменени входни препратки като const.
  2. Това предполага, че всички низове са дълги поне колкото първия. Ако това не е валидно, поведението на кода е недефинирано. За "производствен" код трябва да включите проверка за дължината преди извличане на iтия елемент от всеки низ.
person Matthew Lundberg    schedule 10.11.2013