如何检查一组规则/条件的数据集以进行分类?

时间:2017-01-30 18:30:27

标签: c++ pattern-matching

我有一组银行帐户条目,我存储在我定义的类bankAccountEntry的实例中。类bankAccountEntry具有数据成员

unsigned int year;
unsigned int month;
unsigned int day;
std::string name;
std::string accountNumberConsidered;
std::string  accountNumberContra;
std::string code;
double amount;
std::string sortOfMutation;
std::string note;

我想对这些银行帐户条目进行分类。

例如,如果std::string name包含子字符串gasolineStation1gasolineStation2,则应将其归类为gasoline。为了实现这种分类,我可以通过语句

检查数据成员
if (std::count(bae.name.begin(), bae.name.end(),"gasolineStation1")>0
    || 
    std::count(bae.name.begin(), bae.name.end(),"gasolineStation2")>0)
{
    bae.setCategory("gasoline");
}

对于我所有银行账户分录的分类,我有一大堆这样的预定义规则/条件,我想将其作为主程序的输入参数。

有哪些策略可以检查我的每个银行帐户条目中的规则/条件,直到找到匹配为止?

1 个答案:

答案 0 :(得分:2)

如果大,如果在这里,所有规则都是简单的名称 - 类别映射,这可以相当干净地完成。如果规则不同......哎呀。

暂时只关注简单的案例,

为便于阅读和解释定义:

struct mapping
{
    std::string name;
    std::string category;
}

使用std::pair<std::string,std::string>代替可能有战术优势。并定义

std::vector<mapping> mappings;

将规则文件中的名称 - 类别配对读入mappings。无法就此提出任何建议,因为我们不知道规则是什么样的。一旦完成,

bool bankAccountEntry::categorize()
{
    for (const mapping & kvp: mappings)
    {
        if (name.find(kvp.name) != std::string::npos)
        {
            setCategory(kvp.category);
            return true;
        }
    }
    return false;
}

这是蛮力。根据数据的外观,例如,如果它严格遵循命名方案,您可以真正加快速度。

如果规则更复杂,你可以选择以下内容:

struct mapping
{
    std::function<bool(const bankAccountEntry&)> rule;
    std::string category;
}

std::vector<mapping> mappings;

每个mapping::rule都是一个函数,它接受bankAccountEntry并决定bankAccountEntry是否符合规则。例如:

bool gasolineStationRule(const bankAccountEntry& bae)
{
    return std::count(bae.name.begin(), bae.name.end(),"gasolineStation1")>0 ||       
           std::count(bae.name.begin(), bae.name.end(),"gasolineStation2")>0;
}

哪个不会工作because std::count doesn't work like that

这样的东西
bool gasolineStationRule(const bankAccountEntry& bae)
{
    return (bae.name.find("gasolineStation1")!= std::string::npos) ||
           (bae.name.find("gasolineStation2")!= std::string::npos);
}

会,但可以通过搜索一次&#34; gasolineStation&#34;来改进。然后,如果&#34; gasolineStation&#34;找到,测试后面的字符为&#39; 1&#39;或者&#39; 2&#39;。

如何将rule放入向量中将非常有趣。它可能需要大量的专业功能,一群Lambdas或一对树中的鹧。在问题中没有明确说明肯定。

它可能看起来像

mappings.push_back(mapping{&gasolineStationRule, "gasoline"})

或向mapping

添加构造函数
mapping(std::function<bool(const bankAccountEntry&)> newrule,
        std::string newcategory): rule(newrule), category(newcategory)
{

}

你可以从

获得小的性能提升
mappings.emplace_back(&gasolineStationRule, "gasoline")

总之...

bool bankAccountEntry::categorize()
{
    for (const mapping & kvp: mappings)
    {
        if (kvp.rule(*this))
        {
            setCategory(kvp.category);
            return true;
        }
    }
    return false;
}

同样,您对规则的了解越多,它们的可预测性就越高,您就可以进行优化。

Also look at std::find_if可能会替代bankAccountEntry::categorize的胆量。

Documentation on std::function.