Проблема с функцией std :: sort. Кажется, всегда иметь нулевое значение для 1 элемента после 2 раундов итерации - PullRequest
1 голос
/ 08 ноября 2019

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

Это дает мне ошибку

завершить вызов после броска экземпляра 'std :: out_of_range'
what (): basic_string :: at: __n (который равен 0)> = this-> size () (который равен 0)

При выполнении отладки часть кода для чтения, кажется, функционирует. Считывание содержимого файла в данные DataContainer заполняется правильными данными ключа и положения текста. Но когда дело доходит до std :: sort, когда вызывается программа "less", const GridLabel & elem2 всегда оказывается равным нулю или нулю после 2-й итерации

Ниже приведен некоторый набор данных и частичный исходный код (Iне включайте запись содержимого в отсортированном порядке, но его можно запустить)

Спасибо за помощь!

Это частичный набор данных

Grid_Id,Speed,Acc,ID
K31,173,8.37,1
K29,143,3.36,2
K29,107,4.56,3
K30,133,5.97,4
K30,153,2.38,5
J27,203,1.86,6
J27,143,1.59,7
I26,73,7.66,8
I27,134,2.86,9

Этокод

#include <algorithm>
#include <functional>
#include <fstream>
#include <string>

#include <deque>
#include <vector>

#include <iostream>
#include <sstream>

struct GridLabel
{
    std::string key_;
    std::istream::pos_type pos_;        // position in stream where this line starts

    GridLabel( const std::string& key, const std::istream::pos_type& pos) : key_( key)
                                                                   , pos_( pos)
    {
    }

    const GridLabel& operator=( const GridLabel& other)
    {
        key_ = other.key_;
        pos_ = other.pos_;

        return *this;
    }
};

typedef std::vector<  GridLabel> DataContainer;

// Return whether first element is smaller than the second
bool less( const  GridLabel& elem1, const  GridLabel& elem2 )
{
   std::stringstream ss1, ss2;
   ss1 <<  elem1.key_.at(0);
   ss2 <<  elem2.key_.at(0);

   int value  = (ss1.str()).compare(ss2.str());

   if( value < 0 )
   {
       return true;
   }
   else if( value == 0)
   {
       // need to check if the rest are smaller
       std::string substr1 = elem1.key_.substr(1, std::string::npos);
       std::string substr2 = elem2.key_.substr(1, std::string::npos);

       return (std::atoi(substr1.c_str()) < std::atoi(substr2.c_str()));
   }
   else
   {
       return false;
   }
 }

int main(int argc, char* argv[])
{
   DataContainer data;

   // read data into the vector here
   std::ifstream input( "some_file.csv");

   // check if it is correct
   if ( !input.good())
   {
        std::cerr << "Input file can not be openned." << std::endl;
        return -1;
   }

   std::string text;
   std::string key;
   std::istream::pos_type pos;
   int count=0, save=0;

   // to skip the header
   std::getline( input, text);

   for( int line = 0; !input.eof(); ++line)
   {
      // store the position before reading the line
      pos = input.tellg();

      std::getline( input, text);

      // parse it
      save = text.find(",");

      key = text.substr(0,(save));

      data.push_back(  GridLabel( key, pos));
   }

   // sort the data in sorted order
   std::sort( data.begin(), data.end(), less);

   // create the new file
   ...............

   return 0;
}

1 Ответ

1 голос
/ 08 ноября 2019

Упрощенный less() для сравнения

  1. первые символы GridLabel::key
  2. целое число, начинающееся с 2 nd символ GridLabel::key.

Это не будет учитывать то, что еще хранится в GridLabel::key. (Это может подразумеваться OP.)

Образец:

#include <algorithm>
#include <iostream>
#include <string>

struct GridLabel {
  std::string key;
};

bool less(const GridLabel &elem1, const GridLabel &elem2)
{
  // compare first chars of keys
  const char c1 = elem1.key.at(0), c2 = elem2.key.at(0);
  if (c1 != c2) return c1 < c2;
  // compare integral beginning in 2nd char of keys
  const int i1 = atoi(elem1.key.c_str() + 1);
  const int i2 = atoi(elem2.key.c_str() + 1);
  return i1 < i2;
}

int main()
{
  GridLabel data[] = {
    { "K31,173,8.37,1" },
    { "K29,143,3.36,2" },
    { "K29,107,4.56,3" },
    { "K30,133,5.97,4" },
    { "K30,153,2.38,5" },
    { "J27,203,1.86,6" },
    { "J27,143,1.59,7" },
    { "I26,73,7.66,8" },
    { "I27,134,2.86,9" }
  };
  { std::cout << "Original data:\n";
    int i = 0;
    for (const GridLabel &entry : data) {
      std::cout << i++ << ": '" << entry.key << "'\n";
    }
  }
  std::cout << "Sorting...";
  std::sort(std::begin(data), std::end(data), less);
  std::cout << " Done.\n";
  { std::cout << "Sorted data:\n";
    int i = 0;
    for (const GridLabel &entry : data) {
      std::cout << i++ << ": '" << entry.key << "'\n";
    }
  }
}

Выход:

Original data:
0: 'K31,173,8.37,1'
1: 'K29,143,3.36,2'
2: 'K29,107,4.56,3'
3: 'K30,133,5.97,4'
4: 'K30,153,2.38,5'
5: 'J27,203,1.86,6'
6: 'J27,143,1.59,7'
7: 'I26,73,7.66,8'
8: 'I27,134,2.86,9'
Sorting... Done.
Sorted data:
0: 'I26,73,7.66,8'
1: 'I27,134,2.86,9'
2: 'J27,203,1.86,6'
3: 'J27,143,1.59,7'
4: 'K29,143,3.36,2'
5: 'K29,107,4.56,3'
6: 'K30,133,5.97,4'
7: 'K30,153,2.38,5'
8: 'K31,173,8.37,1'

Живая демонстрация на coliru

Обратите внимание, что (в зависимости от того, как реализован предикат less()) существует множество элементов, которые считаются равными:

  • I26,73,7.66,8 с I27,134,2.86,9
  • J27,203,1.86,6 с J27,143,1.59,7
  • и т. Д.

Эти элементы будут отображаться в произвольном порядке после сортировки.

В качестве альтернативы *Можно использовать 1046 *std::stable_sort(), что сохранит первоначальный порядок в этих случаях.

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