比较具有不同类型值的两个集合 [英] Comparing two sets with different type of values
问题描述
这是要求:
我有一个属性列表。每个属性都有一个int类型的标签,并且有以下类型之一的值:(bool,char,string,int,long)。
一些示例属性:
标记:1,值:某个字符串
标记:14 ,value:true
标签:20,值:123
还有一个规则列表。每个规则都像一个属性,加上下列运算符之一:(<>,< =,> =,==,!=,startsWith)。
一些示例规则:
$ b $ b
tag:1,value:hello,operator:==
tag:14,value:true,operator:==
每个规则列表称为 Criteria
,用于验证属性列表。如果只满足条件的所有规则,则条件验证属性列表。例如,上面的两个规则构成了一个标准。此标准不验证上述属性列表,因为第一个规则强制tag(1)的值等于(==)为hello,而不是。
以下条件:
标记:1,值: ,operator:==
tag:20,value:100,operator:>
tag:20,value:120,operator:<
也不会验证上述属性,因为虽然满足前两个规则,但最后一个规则强制tag(20)的值小于120不是真的。因此,整个标准不会验证属性。
这里是一个验证为true的条件:
:1,value:some,operator:startsWith
tag:14,value:false,operator:!=
tag:20,value:123,operator:
tag:20,value:100,operator:>
到目前为止,码。但我被困在执行 StartsWith
运算符。也许我应该选择一个完全不同的方法来解决这个问题。任何建议和帮助将非常感谢!
#include< string>
#include< iostream>
#include< set>
#include< algorithm>
#include< tr1 / memory>
using namespace std;
///////////////////物业类/////////////////////// /
class Property
{
public:
enum Operator
{
EQ,// ==
NEQ, /!=
GT,//>
GTE,//> =
LT,//<
LTE,//< =
SW,//以
开头} mOperator;
Property(){};
属性(const int tag,Operator op)
:mTag(tag),mOperator(op){}
virtual〜Property(){}
virtual void * GetValue = 0;
virtual bool IsEqual(void * value)= 0;
virtual bool比较(void * value,Property :: Operator op)= 0;
virtual void Print()= 0;
int mTag;
bool operator<(const Property& property)const
{
return mTag< property.mTag;
}
};
struct PropertyPtrComp
{
bool operator()(const std :: tr1 :: shared_ptr< Property> lhs,const std :: tr1 :: shared_ptr< Property> rhs)const
{
return lhs-> mTag< rhs→mTag;
}
};
/////////////////// TypedProperty Class /////////////////
template<类型名T>
class TypedProperty:public Property
{
public:
TypedProperty(const int tag,const T& value,Property :: Operator op)
: opal),mValue(value){}
void * GetValue()
{
return& mValue;
}
bool IsEqual(void * value)
{
return *((T *)value)== mValue;
}
bool比较(void * value,Property :: Operator op)
{
// cout< 比较<< *((T *)值) with<< mValue<< endl;
switch(op)
{
case Property :: EQ:
return *((T *)value)== mValue;
case Property :: NEQ:
return *((T *)value)!= mValue;
case属性:: GT:
return mValue> *((T *)值);
case Property :: LT:
return mValue< *((T *)值);
case Property :: SW:
{
if(typeid((T *)value)== typeid(string *))
{
//不知道该怎么办!
// return((string)mValue).compare(0,(string *)value) - > length(),(string)
}
}
默认值:
return *((T *)value)== mValue;
}
}
void Print()
{
cout< Tag:< mTag < ,值:< mValue<< endl;
}
T mValue;
};
////////////////////////////////////////// ///////////////
typedef std :: tr1 :: shared_ptr< Property> PropertyPtr;
/////////////////// PropertyList类/////////////////
class PropertyList
{
public:
PropertyList(){};
virtual〜PropertyList(){};
template< class T>
void Add(int tag,T value,Property :: Operator op = Property :: EQ)
{
PropertyPtr ptr(new TypedProperty< T&
mProperties.insert(ptr);
}
void Print()
{
cout< -----------<< endl;
for(set< PropertyPtr> :: iterator itr = mProperties.begin(); itr!= mProperties.end(); itr ++)
{
(* itr) - > );
}
}
set< PropertyPtr,PropertyPtrComp>性能;
};
////////////////////检查子集////////////////////// ///
/ *
*检查子集中是否包含子集
* /
bool CheckSubset(set< PropertyPtr,PropertyPtrComp>& superset,
set< Property(); propertyPtrComp>& subset)
{
if(subset.size()> superset.size()|| subset.empty())return false;
typename set< PropertyPtr> :: iterator litr = superset.begin();
for(typename set< PropertyPtr> :: iterator ritr = subset.begin(); ritr!= subset.end();)
{
while(litr!= superset.end ))
{
PropertyPtr lProp =(PropertyPtr)* litr;
PropertyPtr rProp =(PropertyPtr)* ritr;
if(lProp-> mTag == rProp-> mTag)
{
if(lProp-> Compare(rProp-> GetValue(),rProp-> mOperator) )
{
litr ++;
break;
}
return false;
}
else
{
litr ++;
}
}
ritr ++;
if(litr == superset.end()&& ritr!= subset.end())return false;
}
return true;
}
int main()
{
PropertyList属性;
string s =bye;
properties.Add(1,hello);
properties.Add(2,12);
properties.Add(3,34);
properties.Add(4,bye);
properties.Print();
PropertyList ruleSet1;
ruleSet1.Add(2,12,Property :: EQ);
ruleSet1.Add(4,bye,Property :: EQ);
ruleSet1.Print();
if(CheckSubset(properties.mProperties,ruleSet1.mProperties))
cout<< RuleSet1 verified! << endl; //<<<<应该打印
else
cout<< RuleSet1未验证! << endl;
PropertyList ruleSet2;
string hel =hel;
ruleSet2.Add(1,hel,Property :: SW);
ruleSet2.Add(2,13,Property :: NEQ);
ruleSet2.Print();
if(CheckSubset(properties.mProperties,ruleSet2.mProperties))
cout<< RuleSet2 verified! << endl; //<<<<应该打印
else
cout<< RuleSet2未验证! << endl;
}
不要使用void *,请尝试boost :: variant。构建对每个操作符进行操作的测试函子。您比较的值是另一个变体。你可能需要函子的函子,所以你可以做任何转换你想做的两个变体之间。
这种类型和存储从每种类型的算法分离。
你的测试然后成为一对标记和 std :: function< bool
一个例子,只有两种类型。
p>从int到变体开始: typedef std :: map< int,boost :: variant< int,string> MyMap
。
现在进行测试。一个测试是3个东西 - 一个id,一个值(它是一个变体)和一个测试来比较该变体与数据。如果我们不允许字符串和整数相等,我们得到:
template< typename T&
struct CheckOneTypeEquality
{
T const * value;
bool operator()(T const& other)const
{
return other == * value;
}
template< typename U>
bool operator()(U const& other)const
{
return false;
}
CheckOneTypeEquality(T const& value_):value(& value_){}
};
template< typename Variant>
struct TestVariantEquality
{
Variant * v;
struct FindRightToCompare
{
Variant * other;
template< typename T>
bool operator()(T const& value)const
{
return apply_visitor(* other,CheckOneTypeEquality< T&
}
FindRightToCompare(Variant const& other_):other(other_){}
};
bool operator()(Variant const& other)const
{
return apply_visitor(* v,FindRightToCompare(other));
}
};
...执行编译时检查的等式比较。以上所有在左和右操作数上都有双 apply_visitor
,并且 CheckOneTypeEquality
具有 T
匹配左操作数的类型,右操作数作为 U
传递到 operator()
。
在这种情况下,我们只支持相同类型的相等 - 如果我们想允许 int
和 long
进行比较,我们可以恰当地专门化 CheckOneTypeEquality< T> :: operator ; U>
。
我们还可以通过将 CheckOneTypeEquality
一个非模板类型,并将它传递到 TestVariantEquality
类,除了安排我们正在比较的两种类型的double-dispatch。这意味着 TestVariantEquality
(更好的是,更通用的版本,它接受最终的比较函数作为模板参数)可以写一次,你只需要写a CheckOneTypeEquality
每个比较测试的等效函数。
免责声明:以上代码尚未由我编译,基于快速阅读在线文档。在上面的代码中没有使用命名空间,因为我很懒,但一切都基本上是从 std
或 boost
boost
请注意 TestVariantEquality
或类似的函子)可以用于初始化 std :: function< bool(Variant< ...> const&)>
。因此,生成测试函数的函数应该返回 std :: function< bool(Variant< ...> const&)>
$ b
将要测试的数据加载到属性中。使用类似上面的技术来构建测试。不需要虚拟函数,没有void指针,一切都是编译时类型检查。 Here is the requirement: I've got a list of properties. Each property has a tag of type int and a value of one of the following types: (bool, char, string, int, long).
some sample properties: tag: 1, value: "some string" There is also a list of rules. Each rule is like a property, plus one of the following operators: (<, >, <=, >=, ==, !=, startsWith). The startsWith operator is used to check whether one string starts with another one. Some sample rules: tag: 1, value: "hello", operator: == Each list of rules is called a The following criteria: tag: 1, value: "some string", operator: == does not validate the above properties too, because although the first two rules are met, the last rule, which forces the value of tag (20) to be less than 120 is not true. Therefore the whole criteria does not validate the properties. tag: 1, value: "some", operator: startsWith So far I have come up with the following code. But I am stuck in the implementation of
Do not use void*, try boost::variant. Build test functors that operate on each and every operator. The value you compare to is another variant. You may need functors of functors so you can do whatever conversion you want to do between two variants. This separates type and storage from algorithms on each type. And boost does variant types better than you do. Your tests then become a pair of tag and An example, with only two types. Start with a map from int to variant: Now a test. A test is 3 things -- an id, a value (which is a variant) and a test to compare that variant to the data. If we don't allow strings and ints to be equal, we get: ... which does a compile-time checked equality comparison. All the above does a double In this case, we only support equality of the same type -- if we wanted to allow We can also abstract the above by wrapping the Disclaimer: Above code has not been compiled by me, and is based off a quick reading of online docs. Namespaces are not used in the above code because I was lazy, but everything is basically from Note that Load the data you are testing into the properties. Build the tests using something like the above technique. No virtual functions required, no void pointers, and everything is compile-time type checked. 这篇关于比较具有不同类型值的两个集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!属性应该是
std :: map< int,boost: :variant< blah blah>>
。您的测试应为 std :: multimap< int,std :: function< bool(boost :: variant< blah blah> const&)>>
p>
tag: 14, value: true
tag: 20, value: 123
tag: 14, value: true, operator: == Criteria
and is used to validate a list of properties. A criteria validates a list of properties if only all the rules of the criteria are met. For example, the two rules above make up a criteria. This criteria does not validate the aforementioned list of properties because the 1st rule forces the value of tag (1) to be equal (==) to "hello" which is not.
tag: 20, value: 100, operator: >
tag: 20, value: 120, operator: <
And here is a criteria that validates to true:
tag: 14, value: false, operator: !=
tag: 20, value: 123, operator: >=
tag: 20, value: 100, operator: >StartsWith
operator. Maybe I should of chosen a totally different approach to solve this problem. Any advice and help would be greatly appreciated! #include <string>
#include <iostream>
#include <set>
#include <algorithm>
#include <tr1/memory>
using namespace std;
/////////////////// Property Class //////////////////////
class Property
{
public:
enum Operator
{
EQ, // ==
NEQ, // !=
GT, // >
GTE, // >=
LT, // <
LTE, // <=
SW, // Starts With
} mOperator;
Property() {};
Property(const int tag, Operator op)
: mTag(tag), mOperator(op) {}
virtual ~Property() {}
virtual void* GetValue() = 0;
virtual bool IsEqual(void* value) = 0;
virtual bool Compare(void* value, Property::Operator op) = 0;
virtual void Print() = 0;
int mTag;
bool operator<(const Property &property) const
{
return mTag < property.mTag;
}
};
struct PropertyPtrComp
{
bool operator()(const std::tr1::shared_ptr<Property> lhs, const std::tr1::shared_ptr<Property> rhs) const
{
return lhs->mTag < rhs->mTag;
}
};
/////////////////// TypedProperty Class /////////////////
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const int tag, const T& value, Property::Operator op)
: Property(tag, op), mValue(value) {}
void* GetValue()
{
return &mValue;
}
bool IsEqual(void* value)
{
return *((T*)value) == mValue;
}
bool Compare(void* value, Property::Operator op)
{
// cout << "comparing " << *((T*)value) << " with " << mValue << endl;
switch (op)
{
case Property::EQ:
return *((T*)value) == mValue;
case Property::NEQ:
return *((T*)value) != mValue;
case Property::GT:
return mValue > *((T*)value) ;
case Property::LT:
return mValue < *((T*)value) ;
case Property::SW:
{
if (typeid((T*)value) == typeid(string*))
{
// dont know what to do!
//return ((string)mValue).compare(0, ((string*)value)->length(), (string)(*((string*)value)));
}
}
default:
return *((T*)value) == mValue;
}
}
void Print()
{
cout << "Tag: " << mTag << ", Value: " << mValue << endl;
}
T mValue;
};
/////////////////////////////////////////////////////////
typedef std::tr1::shared_ptr<Property> PropertyPtr;
/////////////////// PropertyList Class /////////////////
class PropertyList
{
public:
PropertyList() {};
virtual ~PropertyList() {};
template <class T>
void Add(int tag, T value, Property::Operator op = Property::EQ)
{
PropertyPtr ptr(new TypedProperty<T>(tag, value, op));
mProperties.insert(ptr);
}
void Print()
{
cout << "-----------" << endl;
for (set<PropertyPtr>::iterator itr = mProperties.begin(); itr != mProperties.end(); itr++)
{
(*itr)->Print();
}
}
set<PropertyPtr, PropertyPtrComp> mProperties;
};
//////////////////// Check Subset ///////////////////////
/*
* Checks if subset is included in superset
*/
bool CheckSubset(set<PropertyPtr, PropertyPtrComp> &superset,
set<PropertyPtr, PropertyPtrComp> &subset)
{
if (subset.size() > superset.size() || subset.empty()) return false;
typename set<PropertyPtr>::iterator litr = superset.begin();
for (typename set<PropertyPtr>::iterator ritr = subset.begin(); ritr != subset.end();)
{
while (litr != superset.end())
{
PropertyPtr lProp = (PropertyPtr)*litr;
PropertyPtr rProp = (PropertyPtr)*ritr;
if (lProp->mTag == rProp->mTag)
{
if (lProp->Compare(rProp->GetValue(), rProp->mOperator))
{
litr++;
break;
}
return false;
}
else
{
litr++;
}
}
ritr++;
if (litr == superset.end() && ritr != subset.end()) return false;
}
return true;
}
int main()
{
PropertyList properties;
string s = "bye";
properties.Add(1, "hello");
properties.Add(2, 12);
properties.Add(3, 34);
properties.Add(4, "bye");
properties.Print();
PropertyList ruleSet1;
ruleSet1.Add(2, 12, Property::EQ);
ruleSet1.Add(4, "bye", Property::EQ);
ruleSet1.Print();
if(CheckSubset(properties.mProperties, ruleSet1.mProperties))
cout << "RuleSet1 verified!" << endl; // <<<< should be printed
else
cout << "RuleSet1 NOT verified!" << endl;
PropertyList ruleSet2;
string hel = "hel";
ruleSet2.Add(1, hel, Property::SW);
ruleSet2.Add(2, 13, Property::NEQ);
ruleSet2.Print();
if (CheckSubset(properties.mProperties, ruleSet2.mProperties))
cout << "RuleSet2 verified!" << endl; // <<<< should be printed
else
cout << "RuleSet2 NOT verified!" << endl;
}
std::function<bool(boost::variant<int,long,string,etc>)>
which does the test.typedef std::map<int, boost::variant<int, string>> MyMap
.template<typename T>
struct CheckOneTypeEquality
{
T const* value;
bool operator()( T const& other ) const
{
return other == *value;
}
template<typename U>
bool operator()( U const& other ) const
{
return false;
}
CheckOneTypeEquality( T const& value_ ):value(&value_) {}
};
template<typename Variant>
struct TestVariantEquality
{
Variant* v;
struct FindRightToCompare
{
Variant* other;
template<typename T>
bool operator()( T const& value ) const
{
return apply_visitor( *other, CheckOneTypeEquality<T>(value) );
}
FindRightToCompare( Variant const& other_ ): other(other_) {}
};
bool operator()( Variant const& other ) const
{
return apply_visitor( *v, FindRightToCompare(other) );
}
};
apply_visitor
on both the left and right operands, and CheckOneTypeEquality<T>
has the T
match the type of the left operand, and the right operand is passed in as a U
to the operator()
.int
and long
to compare, we could just appropriately specialize the CheckOneTypeEquality<T>::operator()<U>
.CheckOneTypeEquality
in a non-template type and passing it into the TestVariantEquality
class, which does nothing except arrange for the double-dispatch of the two types we are comparing. Which means that the TestVariantEquality
(well, the more generic version, which takes the final comparison functor as a template parameter) could be written once, and you'd just have to write a CheckOneTypeEquality
equivalent functor for each comparison test.std
or boost
or a sub-namespace of boost
.TestVariantEquality
(or similar functors) can be used to initialize a std::function<bool(Variant<...> const&)>
. So the function that produces the test functions should return std::function<bool(Variant<...> const&)>
, and internally can do the above type of stuff.properties
should be a std::map<int, boost::variant<blah blah>>
. Your tests should be a std::multimap<int, std::function<bool(boost::variant<blah blah> const&)>>
.