问题
I am trying to write a sort program trying to sort a data set I have. The key to the sorting is Grid_ID and it happened to be an alpha-numeric data. I have tried to sort accordingly
It give me an error
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::at: __n (which is 0) >= this->size() (which is 0)
On doing debugging, the reading part of the code seems to function. The reading of file content into DataContainer data get filled with the right data of key and text position. But when it come to std::sort, when the program "less" is invoked, const GridLabel& elem2 always turn up to be zero or null after 2nd iteration
Below is some data set and partial source code (I do not include the write the content in sorted order here but should be runnable)
THanks for help!
This is the partial data set
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
This is the code
#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:
A simplified less()
to compare
- the first characters of
GridLabel::key
- the integral number starting from 2nd character of
GridLabel::key
.
This will not consider what else is stored in GridLabel::key
. (This might be intended by OP.)
Sample:
#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";
}
}
}
Output:
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'
Live Demo on coliru
Please, note that (according to how predicate less()
is implemented) there are a lot elements which are considered as equal:
I26,73,7.66,8
withI27,134,2.86,9
J27,203,1.86,6
withJ27,143,1.59,7
- etc.
These elements will appear in abitrary order after sorting.
Alternatively, std::stable_sort() could be used which will preserve the original order in these cases.
来源:https://stackoverflow.com/questions/58761130/problem-with-stdsort-function-seem-to-always-have-null-value-for-1-element-af