2017-01-30 4 views
1

私は定義したクラス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にサブ文字列gasolineStation1またはgasolineStation2が含まれる場合は、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"); 
} 

文によって、データメンバをチェックすることができ、私は私が望むように事前に定義されたルール/条件の大規模なセットを持っていますメインプログラムへの入力引数として与える。

ヒットが見つかるまで、一連のルール/条件の銀行口座エントリを確認するための戦略はありますか?

答えて

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::rulebankAccountEntrybankAccountEntryを取り、か否かを判断する機能ですルールに適合します。たとえば、

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); 
} 

がしますが、「1」または「2」のためにそれの後に文字をテストし、「gasolineStation」が発見された場合は、「gasolineStation」のために、一度検索してによってに改善することができるように。

ベクターに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_ifbankAccountEntry::categorizeの腸のための可能な置き換えとして。

Documentation on std::function.

+0

あなたは私の 'のstd :: function'の定義の例をお願いできますか?私が言及したルールのために 'std :: function'を定義することができますか?したがって、 'if(std :: count(bae.name.begin()、bae.name.end()、" gasolineStation1 ")> 0 || std :: count(bae.name.begin()、bae。 name.end()、 "gasolineStation2")> 0) 'となります。 – Adriaan

+0

'std :: function'は日常的な普通の関数を包み込み、渡しやすくします。また、['std :: bind'](http://en.cppreference.com/w/cpp/utility/functional/bind)または[ラムダ式](http://en.cppreference .com/w/cpp/language/lambda)。いずれの場合でも、ハードコーディングされた "gasolineStation1"をバインドされた文字列に置き換えるなど、より一般的な機能を特化するのに役立ちます。しかし、それは話題になっています。あなたは新しい質問をするのが良いです。 – user4581301

関連する問題