从对象列表中获取具有特定成员值的所有对象

时间:2017-04-18 07:49:54

标签: c++ sorting search std

从矢量

std::vector<S> structures;

包含

类型的结构
struct S {
    double x;
    double y;
    double weight;
};

我想反复获取具有特定权重的所有结构,即我想执行以下伪代码:

do 1000 times:
   weight = GetASpecificWeight()
   MatchingStructures = structures.GetAllStructuresWithWeight(weight) 

为了有效地做到这一点,我想对structures向量进行排序,并在每次迭代中进行二进制搜索。

如何使用std :: code实现此功能?

1 个答案:

答案 0 :(得分:1)

可以使用std::sort对矢量进行排序,并且可以使用std::equal_range查找具有指定权重的元素范围。

但是,正如Daniel在评论中指出的那样,getASpecificWeight()很可能会返回一个双精度而不是Structure,所以为了调用equal_range,我们需要创建一个dummy Structure或将doubleStructures与所需语义进行比较的函数对象。单个lambda不起作用,因为二进制搜索需要能够将Structure s与两种权重进行比较。

备选方案1:使用虚拟结构

首先,让我们创建一个虚拟Structure,因为这是更少的代码。

总的来说,它可能看起来像这样

auto sort_structure_by_weight_asc = [](Structure const& s1, Structure const& s2) {
    return s1.weight < s2.weight;
};

std::sort(structures.begin(), structures.end(),
          sort_structure_by_weight_asc);

for (auto i = 0; i < 1000; ++i) {
    auto weight = GetASpecificWeight();

    auto const dummy_structure = Strucutre{0.0, 0.0, weight};  
    auto range = std::equal_range(structures.cbegin(), structures.cend(),
                                  dummy_structure, sort_structure_by_weight_asc);

    if (range.first != structures.cend() && range.second != structures.cbegin()) {
       // do whatever you want here
       // if the `if`-condition isn't satisfied, no structure
       // had weight `weight`.
    }
}                               

如果您需要修改structures向量中的元素,可以在调用cbegincend时替换std::equal_rangeif - 条件分别为begin / end

备选方案2:手工制作的功能对象

但是,我个人认为创建虚拟结构非常干净,所以让我们看看自定义函数对象如何改进代码。

函数对象本身可以定义为

struct ComparatorStructureToWeightAsc {
    bool operator()(Structure const& s, double weight) const {
        return s.weight < weight;
    }

    bool operator()(double weight, Structure const& s) const {
        return weight < s.weight;
    }
};

然后代码看起来像这样:

std::sort(structures.begin(), structures.end(),
          [](auto const& s1, auto const& s2) { return s1.weight < s2.weight; });

for (auto i = 0; i < 1000; ++i) {
    auto weight = GetASpecificWeight();

    auto range = std::equal_range(structures.cbegin(), structures.cend(),
                                  weight, ComparatorStructureToWeightAsc);

    if (range.first != structures.cend() && range.second != structures.cbegin()) {
       // do whatever you want here
       // if the `if`-condition isn't satisfied, no structure
       // had weight `weight`.
    }
}                

备选3:使用Boost.Functional / OverloadedFunction

正如你所看到的那样,我不善于命名,所以必须命名用于将Structures与权重进行比较的函数对象有点尴尬,特别是如果它只在这个地方使用的话。如果您可以访问Boost,特别是Boost.Functional/OverloadedFunction,则可以使用两个lambda而不是手工制作的函数对象。

然后代码如下:

std::sort(structures.begin(), structures.end(),
          [](auto const& s1, auto const& s2) { return s1.weight < s2.weight; });

for (auto i = 0; i < 1000; ++i) {
    auto weight = GetASpecificWeight();

    auto range = std::equal_range(structures.cbegin(), structures.cend(), weight, 
                                  boost::make_overloaded_function(
                                    [](Structure const& s, double weight) { return s.weight < weight; },
                                    [](double weight, Structure const& s) { return weight < s.weight; }));

    if (range.first != structures.cend() && range.second != structures.cbegin()) {
       // do whatever you want here
       // if the `if`-condition isn't satisfied, no structure
       // had weight `weight`.
    }
}