std :: list和std :: map的常用算法?

时间:2009-12-14 03:18:32

标签: c++ algorithm list stl map

我有一类兴趣(称之为X) 我有一个std :: list< X *> (称之为L) 我有一个功能(称之为F)。

F(L)根据检查列表中每个X的内部状态的算法返回L的子集(std :: list< X *>)。

我正在向我的应用程序添加一个std :: map< int,X *> (称之为M),我需要定义F(M)以与F(L)相同的方式操作 - 也就是说,F(M)必须返回std :: list< X *>同样,通过检查地图中每个X的内部状态来确定。

作为一个自我描述的懒惰程序员,我立即看到该算法将[逻辑]相同,并且每个数据类型(std :: list和std :: map)都是可迭代的模板。我不想两次保持相同的算法,但我不确定如何继续前进。

一种方法是从F(M)中取出X *(即键值映射中的'值'),将它们放入std :: list< X *>中,将处理过去到F(std :: list< X *>),传递返回std :: list< X *&gt ;;回过头来。我看不出这是唯一的方法。

我的问题:如何在一个地方维护核心算法,但保留迭代序​​列或对关联容器的值的能力?

谢谢!

5 个答案:

答案 0 :(得分:7)

首先,除std::remove_copy_if之外,两者的条件都可以完成。尽管名称remove_copy_if,但不会删除原始集合中的任何内容。我认为,如果它被称为filtered_copy,人们会更容易理解它。它将元素从一个集合复制到另一个集合。对于每个元素,它调用一个谓词,当且仅当谓词为该元素返回false时才复制该项。

这使您只有一个责任:实现查看每个X *的测试函数,并说明是否应将其排除在您正在制作的副本之外。由于您希望以两种不同的方式应用一个逻辑,因此我将逻辑封装在类的私有函数中。这两种方式可以作为类的operator()的重载版本提供给外部世界:

class F { 
    bool do_test(X const *x) const { return x.internal_stuff; }
public:
    bool operator()(X const *x) const { return do_test(x); }

    bool operator()(std::pair<int, X const *> const &p) const { 
        return do_test(p.second);
    }
};

由于operator()(X const *)do_test()的纯粹笨蛋,你可能想摆脱它,但IMO可能弊大于利。

在任何情况下,这都会将您的逻辑完全放在一个地方(F::do_test)。它还提供了一种简单,一致的语法,用于创建list<X *>std::map<int, X *>的过滤副本:

std::list<X *> result;   
std::remove_copy_if(coll.begin(), coll.end(), std:back_inserter(result), F());

最后一点:std::list可能是现存最常用的集合。虽然它确实有它的用途,但它们确实非常罕见。 <{1}}和std::vector 非常经常更好。

答案 1 :(得分:2)

编写一个函数,接受两个正向迭代器作为它的参数(开头和结尾),然后函数只测试迭代器的值,如果它通过测试就将它添加到列表中,递增迭代器,并测试它没有到达终点(如果确实如此,就会中断。)

然后你只需调用该函数并将其传递给集合的begin()和end()迭代器。

答案 2 :(得分:1)

如下:

template<typename T>
struct func {
    std::list<T>& r;
    func(std::list<T>& r_) : r(r_) {}

    bool algorithm(const T& t) {
        return t<5; // obviously meant to be replaced :)
    }

    void operator()(const T& t) {
        if (algorithm(t)) r.push_back(t);
    }

    void operator()(const std::pair<int, T>& t) {
        if (algorithm(t.second)) r.push_back(t.second);
    }

};

template<typename T, typename ForwardIterator>
std::list<T> subset(ForwardIterator begin, ForwardIterator end) {
    std::list<T> r;
    std::for_each(begin, end, func<T>(r));
    return r;
}

答案 3 :(得分:0)

一种解决方案是将算法从两个函数中移出,这些函数只是迭代它们的容器,并调用算法函数来确定特定项是否属于返回列表。

答案 4 :(得分:0)

你可能是对的,你建议的方法不是唯一的解决方案,但它可能是最容易正确编写和理解的。如果您正在编写生产代码,我肯定会从那里开始。只有在您需要时才能分析代码并获得更好的效果。

在探索其他选项时,您可以查看boost::bind。当我试图做一些类似的事情时,我收到了this answer。我认为std::tr1::bind基本相同,所以如果你没有Boost,你应该可以替换TR1版本。