我有std :: strings包含我需要排序的前导部分中的数字。数字可以是整数或浮点数。
vector<std::string>
排序不是最佳的,我发现以下自然分类程序要好得多。我仍然有一个小问题,小于零的数字不合适。有没有人有改进的建议?我们正在使用Visual Studio 2003。
完整的程序如下。
TIA, 伯特
#include <list>
#include <string>
#include <iostream>
using namespace std;
class MyData
{
public:
string m_str;
MyData(string str) {
m_str = str;
}
long field1() const
{
int second = m_str.find_last_of("-");
int first = m_str.find_last_of("-", second-1);
return atol(m_str.substr(first+1, second-first-1).c_str());
}
long field2() const
{
return atol(m_str.substr(m_str.find_last_of("-")+1).c_str());
}
bool operator < (const MyData& rhs)
{
if (field1() < rhs.field1()) {
return true;
} else if (field1() > rhs.field1()) {
return false;
} else {
return field2() < rhs.field2();
}
}
};
int main()
{
// Create list
list<MyData> mylist;
mylist.push_front(MyData("93.33"));
mylist.push_front(MyData("0.18"));
mylist.push_front(MyData("485"));
mylist.push_front(MyData("7601"));
mylist.push_front(MyData("1001"));
mylist.push_front(MyData("0.26"));
mylist.push_front(MyData("0.26"));
// Sort the list
mylist.sort();
// Dump the list to check the result
for (list<MyData>::const_iterator elem = mylist.begin(); elem != mylist.end(); ++elem)
{
cout << (*elem).m_str << endl;
}
return 1;
}
GOT:
0.26
0.26
0.18
93.33
485
1001
7601
预期:
0.18
0.26
0.26
93.33
485
1001
7601
答案 0 :(得分:2)
使用atof()
代替atol()
进行比较,将数字的小数部分考虑在内。您还需要将返回类型更改为双精度。
答案 1 :(得分:1)
如果它只是浮点字符串,我宁愿建议创建一个包含两列的表(第一行包含原始字符串,第二行用转换为float的字符串填充),按浮点列排序然后输出/使用已排序的字符串列。
答案 2 :(得分:0)
如果数据都是数字,我会创建一个新类来包含数据。
它可以有一个字符串来包含数据,但随后允许您有更好的方法来建模行为 - 在这种情况下,特别是为了实现运算符&lt;
该实现还可以包括使用计算精确值的库,例如GNU multiple precision这会从字符串进行比较和反转(或者如果数字没有那么多可以使用双重数字的重要数字)
答案 3 :(得分:0)
我会计算一次值并存储它们 因为它们实际上不是对象状态的一部分(它们只是计算值),所以将它们标记为可变。然后它们也可以在const方法中设置。
另请注意,MyClass本身就是朋友,因此可以访问同一个类的另一个对象的私有成员。因此,不需要极端的访问方法。记住Accessor方法是保护其他类免受实现中的更改而不是您正在实现的类。
排序的问题是atoi()只读取整数(即它停在'。'字符。因此,所有小于0的数字都有一个零值用于比较,因此它们将以随机顺序出现。要比较全部值,需要将它们作为浮点值(双精度)提取。
class MyData
{
private:
mutable bool gotPos;
mutable double f1;
mutable double f2;
public:
/*
* Why is this public?
*/
std::string m_str;
MyData(std::string str)
:gotPos(false)
,m_str(str) // Use initializer list
{
// If you are always going to build f1,f2 then call BuildPos()
// here and then you don't need the test in the operator <
}
bool operator < (const MyData& rhs)
{
if (!gotPos)
{ buildPos();
}
if (!rhs.gotPos)
{ rhs.buildPos();
}
if (f1 < rhs.f1) return true;
if (f1 > rhs.f1) return false;
return f2 < rhs.f2;
}
private:
void buildPos() const
{
int second = m_str.find_last_of("-");
int first = m_str.find_last_of("-", second-1);
// Use boost lexical cast as it handles doubles
// As well as integers.
f1 = boost::lexical_cast<double>(m_str.substr(first + 1, second-first - 1));
f2 = boost::lexical_cast<double>(m_str.substr(second + 1));
gotPos = true;
}
};