C ++将一堆值与给定值进行比较

时间:2009-03-12 16:47:54

标签: c++

我需要将一个给定值与检索到的值进行比较。我在代码中多次这样做。我不满意它的外观,我正在寻找某种类型的util函数。有谁写过一个?

我在比较的值的数量在编译时是已知的。

更新:我想摆脱容器,因为我知道确切的数值(通常不超过3)我想与之比较。每次将物品放入容器都不太方便 我不喜欢 if ,因为它并不像“查找”那样明显。

#include <algorithm>
#include <string>
#include <vector>

std::string getValue1()
{
    return "test";
}

std::string getValue2()
{
    return "the";
}

std::string getValue3()
{
    return "world";
}

int main()
{
    const std::string value = "the";

    // simple if
    if ( value == getValue1() ||
         value == getValue2() ||
         value == getValue3() )
        return 1;

    // using collections like vector, set
    std::vector<std::string> values;
    values.push_back( getValue1() );
    values.push_back( getValue2() );
    values.push_back( getValue3() );
    if ( values.end() != std::find( values.begin(), values.end(), value ) )
        return 1;

    // third option I'd use instead
    //

    return 0;
}

10 个答案:

答案 0 :(得分:7)

如果您要查找的值与运营商的比较&lt; (比如int,float和std :: strings),那么使用std :: set将值放在那里然后检查set.find(value)== set.end()会更快。这是因为该集合将以特定顺序存储值,以便更快地进行查找。使用哈希表会更快。但是,对于少于50个值或者你可能没有注意到任何差异:)所以我的经验法则是:

  • 少于5项:如果有多个||

  • 5个或更多:放入集合或哈希表

答案 1 :(得分:3)

您可以编写一组模板函数来帮助您完成此操作,例如:

template <typename T>
bool InSet(const T & item, const T & i1, const T & i2) {
  return item==i1 || item==i2;
}

template <typename T>
bool InSet(const T & item, const T & i1, const T & i2, const T & i3) {
  return item==i1 || item==i2 || item==i3;
}

请注意,通过创建具有不同数量参数的多个模板,可以使InSet像使用可变数量的参数一样工作。

然后:

int i;
if (InSet(i, 3, 4, 5)) { ... }
string s;
if (InSet(s, "foobar", "zap", "garblex")) { ... }

答案 2 :(得分:1)

std :: set std :: vector 。只需使用 std :: set_intersection() ...

代码最好......

#include <set>
#include <iostream>
#include <iterator>
using namespace std;

#define COUNT(TYPE,ARRAY)  ( sizeof(ARRAY) / sizeof(TYPE) )

inline bool CaseInsensitiveCompare (const char * a, const char * b)
  {  return strcasecmp( a, b ) < 0;  }

int  main()
{
  const char * setA[] = { "the", "world", "is", "flat" };
  const char * setB[] = { "the", "empty", "set", "is", "boring" };

  stable_sort( setA,  setA + COUNT( const char *, setA ),
               CaseInsensitiveCompare );

  stable_sort( setB,  setB + COUNT( const char *, setB ),
               CaseInsensitiveCompare );

  cout << "Intersection of sets:  ";
  set_intersection( setA, setA + COUNT( const char *, setA ),
                    setB, setB + COUNT( const char *, setB ),
                    ostream_iterator<const char *>(cout, " "),
                    CaseInsensitiveCompare );
  cout << endl << endl;
}

或许,考虑到你的1-N查找问题:
(注意:使用 binary_search() AFTER 排序!)

if ( binary_search( setA, setA + COUNT( const char *, setA ),
            "is", CaseInsensitiveCompare ) )
  ...

if ( binary_search( setA, setA + COUNT( const char *, setA ),
            "set", CaseInsensitiveCompare ) )
  ...

答案 3 :(得分:1)

根据您的要求

if (InSet(value)(GetValue1(), GetValue2(), GetValue3()))
{
   // Do something here...
}

试试这个:

template <typename T>
class InSetHelper
{
     const T &Value;
     void operator=(const InSetHelper &);
public:
     InSetHelper(const T &value) : Value(value) {}

     template<class Other, class Another>
     bool operator()(const Other &value1, const Another &value2) const
     {
         return Value == value1 || Value == value2;
     }
     template<class Other, class Another, class AThird>
     bool operator()(const Other &value1, const Another &value2, const AThird &value3) const
     {
         return Value == value1 || Value == value2 || Value == value3;
     }
};

template <typename T> 
InSetHelper<T> InSet(const T &value) { return InSetHelper<T>(value); }

这种语法可能更清楚:

if (MakeSet(GetValue1(), GetValue2(), GetValue3()).Contains(value))
{
   // Do something here...
}

template <typename T, typename U, typename V>
class Set3
{
    const T& V1;
    const U& V2;
    const V& V3;
    void operator=(const Set3 &);
public:
    Set3(const T &v1, const U &v2, const V &v3) : V1(v1), V2(v2), V3(v3) {}

    template <typename W>
    bool Contains(const W &v) const
    {
        return V1 == v || V2 == v || V3 == v;
    }
};

template <typename T, typename U>
class Set2 
{ 
     // as above 
};

template <typename T, typename U, typename V>
Set3<T, U, V> MakeSet(const T &v1, const U &v2, const V &v3)
{
    return Set3<T, U, V>(v1, v2, v3);
}

template <typename T, typename U>
Set3<T, U> MakeSet(const T &v1, const U &v23)
{
    return Set3<T, U, V>(v1, v2);
}

如果这些值实际上是树或链表的一部分,那么你已经拥有了你的设置/容器,你最好的选择就是使用一些递归:

parent.ThisOrDescendantHasValue(value);

您只需将其添加到父级和子级所属的任何类:

class Node
{
public: 
    Value GetValue();
    Node *GetChild();
    bool ThisOrDescendantHasValue(const Value &value)
    {
        return GetValue() == value
           || (GetChild() && GetChild->ThisOrDescendantHasValue(value));
    }
};

答案 4 :(得分:1)

哪个更改,'value'或'getValueX()'返回的值?您可以将所有内容插入到hash_map / map中,然后按照您对容器的建议进行搜索。

答案 5 :(得分:0)

std::find_first_of

当然,如果您只关心查找单个值,则可以围绕std::find创建自己的包装器。

答案 6 :(得分:0)

我会推荐你​​的方法2,使用std :: vector或其他容器并寻找成员资格。由于您要检查的元素的顺序可能不相关,因此您可能希望使用std :: set或std :: map。如果你的值集合中有很多项目,那么使用集合或地图会更快,而如果只有少数,则矢量可能会更快。

这些方法中的任何一个的优点是,您可以将集合/映射存储在常见的位置,并避免每次都必须构建匹配响应集。

答案 7 :(得分:0)

我喜欢收藏方法,也许使用hash_set而不是vector。将值存储在属性文件中,并具有从文件中填充hash_set的方法,如果值在hash_set中,则返回另一个boolean值。然后你可以在主代码中找到一两行。

答案 8 :(得分:0)

这取决于检索到的值的来源,如果您从文件或流中读入,那么您将执行不同的操作,但如果您的源是一系列函数,那么以下是另一种方法,不完美但可能适合您的需求:

const int count = 3;
std::string value = "world";
boost::function<std::string(void)> funcArray[count];
funcArray[0] = &getValue1;
funcArray[1] = &getValue2;
funcArray[2] = &getValue3;

for( int i = 0; i < count; ++i )
{
    if( funcArray[i]() == value )
        return 1;
}

如果您知道哪些函数是源(以及对象的数量),我希望您可以使用预处理器组装函数指针数组。

答案 9 :(得分:0)

如何使用boost :: array(或std :: tr1 :: array)并创建一个这样的简单函数:

template <typename ValueType, size_t arraySize>
bool contains(const boost::array<ValueType, arraySize>& arr, const ValueType& val)
{
    return std::find(arr.begin(), arr.end(), val)!=arr.end();
}

然后你可以很容易地重复使用它:

#include <string>
#include <iostream>

#include <boost\array.hpp>

template <typename ValueType, size_t arraySize>
bool contains(const boost::array<ValueType, arraySize>& arr, const ValueType& val)
{
    return std::find(arr.begin(), arr.end(), val)!=arr.end();
}

int _tmain(int argc, _TCHAR* argv[])
{
    boost::array<std::string, 3> arr = {"HI", "there", "world"};

    std::cout << std::boolalpha 
        << "arr contains HI: " << contains(arr, std::string("HI")) << std::endl
        << "arr contains blag: " << contains(arr, std::string("blag") ) << std::endl
        << "arr contains there: " << contains(arr, std::string("there") ) << std::endl;

    return 0;
}

编辑:因此提升已经结束。将其调整为常规数组非常容易:

template <typename ValueType, size_t arraySize>
bool contains(ValueType (&arr)[arraySize], const ValueType& val)
{
    return std::find(&arr[0], &arr[arraySize], val)!=&arr[arraySize];
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::string arr[3] = {"HI", "there", "world"};

    std::cout << std::boolalpha << "arr contains HI: " << contains(arr, std::string("HI")) << std::endl
        << "arr contains blag: " << contains(arr, std::string("blag") ) << std::endl
        << "arr contains there: " << contains(arr, std::string("there") ) << std::endl;

    return 0;
}