Сравнение строк с С++

Раньше у меня был код на 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 способ мышления сделать это. Однако я заинтересован в развитии своего мышления на С++, я хотел бы написать что-то, что достигает вышеизложенного: так выясняет, какие символы в 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. Функция должна принимать константную ссылку на вектор, так как входной вектор не изменяется. На самом деле это не проблема, но по разным причинам рекомендуется объявлять неизмененные входные ссылки как константы.
  2. Это предполагает, что все строки не меньше первой. Если это не так, поведение кода не определено. Для «производственного» кода вы должны включить проверку длины перед извлечением i элемента каждой строки.
person Matthew Lundberg    schedule 10.11.2013