【问题标题】:Get all objects with a specific member value from a list of objects从对象列表中获取具有特定成员值的所有对象
【发布时间】:2017-09-13 23:05:15
【问题描述】:

从一个向量

std::vector<S> structures;

包含该类型的结构

struct S {
    double x;
    double y;
    double weight;
};

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

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

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

我如何使用 std:: 代码来实现它?

【问题讨论】:

  • 标准库有一个名为std::sort 的函数,可以满足您的需要。你试过了吗? PS。如果获取权重涉及计算值,请务必意识到浮点值的精确相等比较是没有意义的。
  • std::sort 一次,然后是多个std::equal_range

标签: c++ sorting search std


【解决方案1】:

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

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

备选方案 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向量中的元素,可以将std::equal_rangeif条件调用中的cbegincend分别替换为begin/end .

备选方案 2:手工制作的函数对象

但是,我个人认为创建 dummy struct 不是很干净,所以让我们看看自定义函数对象如何改进代码。

函数对象本身可以定义为

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

如您所见,我不擅长命名事物,因此必须命名用于将结构与权重进行比较的函数对象有点尴尬,特别是如果它只用于这个单一的地方。如果您有权访问 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`.
    }
}                

【讨论】:

  • 这不太正确,因为大概GetASpecificWeight 返回一个double 而不是S。您需要修改比较器。
  • @Daniel True,我解决了这个问题。
  • 抱歉beeing太不具体了:你可以假设GetASpecificWeight()返回一个double,它至少等于一个结构权重。
  • @user1934212 当GetASpecificWeight 返回双精度时,以上三个版本都可以工作。丹尼尔斯评论指的是这个答案的先前版本,我假设它返回一个结构,它 - 给定它的名字 - 应该很明显。
  • @user1934212 单个 lambda 不起作用,因为传递给 std::equal_range 的比较器需要使用参数 Structure, doubledouble, Structure 都可以调用,因为二进制搜索需要比较两种方式。我认为 Boost 版本最能说明问题,因为它定义了所需的两个 lambda。
猜你喜欢
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-29
相关资源
最近更新 更多