在我的代码中,我有一个结构,类似于以下内容:
struct basket {
std::string a;
std::string b;
std::string c;
std::string d;
};
我希望能够比较两个结构并确定> 0,< 0,== 0通过比较所有这些字符串的串联
std::string total = (a+b+c+d);
但是,我希望在不进行实际连接的情况下实现此目的,因为这种比较被多次使用,并且最终成为运行时瓶颈。我知道如果是这样的话,我应该考虑避免使用字符串,但是现在我只想在没有连接的情况下轻松地进行这种比较。
现在,我使用了巨大的if语句。例如,比较结构的每个实例的字符串a,如果它们相同,则比较b,如果它们相同,则比较c,如果它们相同则最后比较d,但我想知道是否存在更简洁的方法在c ++中执行此操作,但没有连续的运行时命中。
谢谢。
答案 0 :(得分:2)
如果我理解正确,如果字符串的串联相等,你希望两个结构相等,所以
a == "hello", b == "there", ...
匹配
a = "hel", b == "lothere", ...
我会使用boost::range::join
执行此操作:
struct basket {
...
bool operator==(const basket& other) const
{
using namespace boost::range;
auto left = join(join(join(a, b), c), d);
auto right = join(join(join(other.a, other.b), other.c), other.d);
return equal(left, right); // http://www.boost.org/doc/libs/1_51_0/libs/range/doc/html/range/reference/algorithms/non_mutating/equal.html
}
};
boost::range::join
(http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/utilities/join.html)创建连接范围而不进行连接。它内部只是一直迭代。唯一的额外开销是检查第一个范围的结束并移动到第二个范围,因此它应该比实际连接快得多。
更新:
我最初错过了strcmp
风格回归的愿望。不幸的是,我无法找到任何返回这样的值的标准算法。不过,在好的方面,写起来很容易。以下是更新版本,compare
代替equal
:
#include <boost/range/join.hpp>
template <typename SinglePassRange1, typename SinglePassRange2>
int compare(const SinglePassRange1& left, const SinglePassRange2& right)
{
using namespace std;
auto leftIt = begin(left);
auto leftEnd = end(right);
auto rightIt = begin(right);
auto rightEnd = end(right);
for ( ; leftIt != leftEnd
&& rightIt != rightEnd
&& *leftIt == *rightIt
; ++leftIt, ++rightIt)
{
}
// should be safe since one-past-end for strings is '\0'
return static_cast<int>(*leftIt) - static_cast<int>(*rightIt);
}
struct basket {
std::string a;
std::string b;
std::string c;
std::string d;
int compare(const basket& other) const
{
using namespace boost::range;
auto left = join(join(join(a, b), c), d);
auto right = join(join(join(other.a, other.b), other.c), other.d);
return ::compare(left, right);
}
};
在GCC 4.9.1 Ubuntu上进行测试。
compare
自由函数应该被称为compareStringRanges
或者其他东西,因为该实现只对字符串有效。我将其留给了个人美学领域。
答案 1 :(得分:0)
使用这些字段的简单方法是使用字段数组&#39;存储,而不是单个字段。
您可以创建一个临时数组来简化代码。您的实现几乎肯定会将std::array
的数据放在堆栈上。
插图:
int compare(const basket &pOther) const {
const BasketStringRefs a(this->allStrings());
const BasketStringRefs b(pOther.allStrings());
// ...your evaluation here, involving iteration over a and b...
}
private:
typedef std::array<const std::string*, 4> BasketStringRefs;
BasketStringRefs allStrings() const {
return BasketStringRefs{{&a, &b, &c, &d}};
}
答案 2 :(得分:0)
设置会很麻烦,但效率很高:将a,b,c和d存储在一个缓冲区中。您可以维护每个指针以跟踪每个开始的位置(或者如果您知道最大尺寸,则将它们存储在相对位置0,最大尺寸,最大尺寸* 2和最大尺寸+ 3)。
当你比较篮子时,比较它们的缓冲区,使用一个上升到缓冲区大小的for循环而不是一个以null字符结尾的while循环。当你得到一个空字符时,你就完成了那个字符串;继续下一个,看看你要比较的下一个字符。如果这种情况发生了4次,你已经阅读了所有4个,并且应该退出那个篮子。
//baskets are a and b
for (int aIndex = 0, bindex = 0; aIndex < MAX && bIndex < MAX; ++aIndex, ++bIndex)
{
//if we reach null char for basket a, skip to next string in basket a. Same for b.
//if we run out of strings in basket a first, it's shorter
// and comes first in alpha order. Same for b.
//if we run out of strings in both baskets without finding any differences,
// return 0 for equal
//compare the next char in each buffer; if different, return -1 or 1 appropriately
}
答案 3 :(得分:0)
我为连接字符串写了一个快速而又脏的迭代器,只是为了好玩:
#include "stdafx.h"
#include <iostream>
#include <assert.h>
class concatenation {
private:
std::string a, b, c, d;
public:
concatenation(){}
concatenation(const std::string &s1, const std::string &s2, const std::string &s3, const std::string &s4)
: a(s1), b(s2), c(s3), d(s4)
{}
class const_iterator {
private:
size_t stringnumber, stringposition;
const concatenation ⌖
public:
const_iterator(const concatenation &r, size_t n, size_t p) : target(r), stringnumber(n), stringposition(p) {}
bool operator ==(const const_iterator &rhs){ return stringnumber == rhs.stringnumber && stringposition == rhs.stringposition; }
bool operator !=(const const_iterator &rhs){ return !(*this == rhs); }
char operator *(){
switch (stringnumber){
case 0: return target.a[stringposition];
case 1: return target.b[stringposition];
case 2: return target.c[stringposition];
case 3: return target.d[stringposition];
default:
return '\0';
}
}
const_iterator& operator ++(){
size_t current_length;
switch (stringnumber){
case 0: current_length = target.a.size(); break;
case 1: current_length = target.b.size(); break;
case 2: current_length = target.c.size(); break;
case 3: current_length = target.d.size(); break;
default:
assert(0);
current_length = 0;
}
if (stringposition < current_length-1){
++stringposition;
} else {
stringposition = 0;
++stringnumber;
}
return *this;
}
};
const_iterator begin() const {
return const_iterator(*this, 0, 0);
}
const_iterator end() const {
return const_iterator(*this, 4, 0);
}
};
int compare(const concatenation &left, const concatenation &right){
concatenation::const_iterator p1 (left.begin());
concatenation::const_iterator p2 (right.begin());
while (p1 != left.end() && p2 != right.end() && (*p1)==(*p2)){
++p1;
++p2;
}
if (*p1 != *p2){
if (p1 == left.end() && p2 != right.end())
return -1;
if (p1 != left.end() && p2 == right.end())
return 1;
if (*p1 < *p2)
return -1;
else
return 1;
}
return 0;
}
int main()
{
concatenation test("hel", "lo ", "wor", "ld.");
for (concatenation::const_iterator pos = test.begin(); pos != test.end(); ++pos)
std::cout << *pos;
std::cout << std::endl;
{
// same
concatenation first("hello", " ", "world", ".");
concatenation second("hel", "lo ", "wor", "ld.");
if (0 != compare(first, second))
assert(0);
}
{
// first character different
concatenation first("hello", " ", "world", ".");
concatenation second("jel", "lo ", "wor", "ld.");
if (-1 != compare(first, second))
assert(0);
if (1 != compare(second, first))
assert(0);
}
{
// middle character different
concatenation first("hello", " ", "world", ".");
concatenation second("hel", "p! ", "wor", "ld.");
if (-1 != compare(first, second))
assert(0);
if (1 != compare(second, first))
assert(0);
}
{
// length different
concatenation first("hello", "", "", "");
concatenation second("hel", "lo ", "wor", "ld.");
if (-1 != compare(first, second))
assert(0);
if (1 != compare(second, first))
assert(0);
}
return 0;
}