C ++ использует множественный фильтр для контейнера с меньшими издержками - PullRequest
0 голосов
/ 29 сентября 2018

Мне нужно отфильтровать контейнер, и копия каждого предмета стоит дорого.Так что я придумал этот код C ++ ... может быть, есть лучшая концепция, которую я скучаю.Прокомментируйте, пожалуйста.Также важно, чтобы такие операции, как подсчет и очистка, также выполнялись быстро.

В приведенном ниже примере будет создан вектор с некоторыми элементами, и будет возвращена отфильтрованная копия с некоторыми логическими операциями.

#include <vector>
#include <functional>

template <class X> struct filterChainT {
    /// the list here
    const X & list;
    /// take store type from access operator 
    typedef decltype(list[0]) storeType;
    /// the test functions
    std::function<bool(storeType &) > tests[10];
    /// counting the test (don´t use array here)
    size_t countTest;

    /// ctor with given list
    filterChainT(const X & list):list(list),countTest(0) { }

    /// add a rule here
    filterChainT<X> & apply(const std::function<bool(storeType &) > & fnc)
    {
        tests[countTest++] = fnc;
        return *this;
    }

    /// downcast to container (will return the filter copy)
    operator X() const 
    { 
        X ret;
        eval([&](const storeType & hit) { ret.push_back(hit); return false; });
        return ret;
    }

    /// just count item after filter
    int count() const
    {
        int count = 0;
        eval([&](const storeType hit) { count++; return false; });
        return count;
    }

    bool operator==(int number) const { return count() == number; }
    bool operator>(int number) const
    {
        int count = 0;
        return eval([&](const storeType & hit) { return ++count>number; });
    }
    bool operator<(int number) const
    {
        int count = 0;
        return !eval([&](const storeType & hit) { return ++count>=number; });
    }

    //// the magic eval functions. Return true if the fnc object abort the loop
    template <class FNC> bool eval(const FNC fnc) const
    {
        for (auto i : list)
        {
            for (size_t t = 0; t < countTest; t++)
            {
                if (!tests[t](i))
                    goto next;
            }
            if (fnc(i))
                return true;
           next:;
        }
        return false;
    }

};

struct myFilter : public filterChainT < std::vector<int>> {

    myFilter(const std::vector<int> & in) :filterChainT<std::vector<int>>(in){ };
    // filter items i%2==0
    myFilter & mod()
    {
        apply([](const int & i) { return i % 2; });
        return *this;
    }
    // filter items smaller than x
    myFilter & smaller(int x)
    {
        apply([=](const int & i) { return i<x; });
        return *this;
    }
};

int main()
{
    std::vector<int> vec;
    vec.push_back(1);
    vec.push_back(3);
    vec.push_back(10);

    // apply filter and return result use two filters „mod“ and „smaller“
    std::vector<int> ret = myFilter(vec).mod().smaller(5);
    // just see if they are less then 2 items in list same filter than above
    bool res1 = myFilter(vec).mod().smaller(5) < 2;
    // some custom without the helper -> filter all items larger than 3 and put in list
    std::vector<int> result=filterChainT < std::vector<int>>(vec).apply([](const int & p) { return p > 3; });
}

в отношении Маркуса

1 Ответ

0 голосов
/ 29 сентября 2018

подсказка с «шаблонами выражений» работает очень хорошо.В два раза быстрее, чем моя публикация.Теперь код выглядит так.Большое спасибо за указание на правильное место.

Я использую ту же концепцию, что и запись WIKI, добавляя операцию плюс для создания цепочки фильтров и конечную функцию для сокращения заданного списка с помощью этого фильтра.

template <class T> struct filterNodeBaseT {
    template <class X> bool apply(const X& x) const { return static_cast<T const & >(*this).apply(x); }

    template <class LST> LST filter(const LST & input) const
    {   LST ret;
        for (auto i : input)
        {   if (this->apply(i))
              ret.push_back(i);
        }
        return ret;
    }

    template <class LST> int count(const LST & input) const
    {   int ret = 0;
        for (auto i : input)
        {   if (this->apply(i))
                ret++;
        }
        return ret;
    }

};

template <class T1, class T2> struct filterCombine : public filterNodeBaseT<filterCombine<T1, T2> > {
    const T1 & t1;
    const T2 & t2;
    filterCombine(const T1 & t1, const T2 & t2) :t1(t1), t2(t2) { }
    template <class X> bool apply(const X & x) const { return t1.apply(x) && t2.apply(x); }
};

template <class T1,class T2> filterCombine<T1,T2> operator + (const T1 & t1,const T2 & t2) 
{ return filterCombine<T1,T2>(t1,t2); }


struct filterNodeSmaller : public filterNodeBaseT<filterNodeSmaller> {
    int limit;
    filterNodeSmaller(int limit) :limit(limit) {};
    bool apply(const int & x) const { return x < limit; }
};

struct filterNodeLarger: public filterNodeBaseT<filterNodeLarger> {
    int limit;
    filterNodeLarger(int limit) :limit(limit) {};
    bool apply(const int & x) const { return x > limit; }
};

struct filterNodeMod : public filterNodeBaseT<filterNodeMod> {
    bool apply(const int & x) const { return x % 2; }
};

struct filterStrlenLarger : public filterNodeBaseT<filterStrlenLarger> {
    int limit;
    filterStrlenLarger(int limit) :limit(limit) { };
    bool apply(const std::string & s) const { return s.length() > limit; }
};

struct filterStrGreater : public filterNodeBaseT<filterStrGreater> {
    std::string cmp;
    filterStrGreater(const std::string & cmp) :cmp(cmp) { };
    bool apply(const std::string & s) const { return s>cmp; }
};

_declspec(noinline) void nodeTest()
{
    std::vector<int> intList;
    intList.push_back(1); intList.push_back(3); intList.push_back(4);
    int count= (filterNodeMod() + filterNodeSmaller(5)+ filterNodeLarger(1)).count(intList);
    std::vector<int> resList1= (filterNodeMod() + filterNodeSmaller(5)+filterNodeLarger(1)).filter(intList);
    printf("%d\n", count);

    std::vector<std::string> strList;
    strList.push_back("Hello");
    strList.push_back("World");
    strList.push_back("!");

    count = (filterStrlenLarger(3)+filterStrGreater("Hello")).count(strList);
    std::vector<std::string> resList2= (filterStrlenLarger(3) + filterStrGreater("Hello")).filter(strList);

    printf("%d\n", count);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...