std::set_union 的替代方法,带有用于合并交集元素的附加谓词参数

Alternative to std::set_union with additional predicate parameter for merging elements from the intersection

提问人:acegene 提问时间:6/23/2021 最后编辑:acegene 更新时间:6/23/2021 访问量:236

问:

给定两个排序的容器和 std::set_union,我们可以提供一个谓词来确定两个元素何时相等。我想提供一个额外的谓词,它将合并相等的元素(容器的交集)并将结果插入到输出容器中。

请注意下面的“预期输出”部分,set_union和unknown_func的向量有何不同。

是否有一种算法可以模拟下面“预期输出”所描述的行为?如果只有更复杂的方法可以产生这种行为,您能建议我从哪里开始这样做吗?最好最终解决方案仅利用 std/stl 库提供的功能。

示例代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

struct CustomStruct{
    CustomStruct(const int f1, const int f2) : field_1(f1), field_2(f2) {}
    int field_1;
    int field_2;
};

void print_vector(const std::string& str, const std::vector<CustomStruct>& vec){
    std::cout << str << std::endl;
    for (const auto& val: vec){
        std::cout<< val.field_1 << ", " << val.field_2 << std::endl;
    }
}


int main()
{
    std::vector<CustomStruct> vec_a;
    std::vector<CustomStruct> vec_b;
    std::vector<CustomStruct> vec_set_union;
    std::vector<CustomStruct> vec_unknown_func;

    for (int i = 0; i < 4; ++i){ vec_a.emplace_back(i, 2); }
    for (int i = 2; i < 4; ++i){ vec_b.emplace_back(i, 3); }
    
    print_vector("VEC_A", vec_a);
    print_vector("VEC_B", vec_b);
    
    const auto compare = [](const CustomStruct& lhs, const CustomStruct& rhs){
        return lhs.field_1 < rhs.field_1;
    };
    std::set_union(vec_a.begin(), vec_a.end(),
                   vec_b.begin(), vec_b.end(),           
                   std::back_inserter(vec_set_union),
                   compare
   );
   
    print_vector("VEC_SET_UNION", vec_set_union);
    
    const auto merge_duplicate = [](const CustomStruct& lhs, const CustomStruct& rhs){
        return CustomStruct(lhs.field_1, lhs.field_2 + (rhs.field_2*rhs.field_2));
    };
    // std::unknown_func(vec_a.begin(), vec_a.end(),
    //                                     vec_b.begin(), vec_b.end(),           
    //                                     std::back_inserter(vec_unknown_func),
    //                                     compare,
    //                                     merge_duplicate
    // );
    
    // THE COMMENTED CODE ABOVE WOULD NEED TO ALLOW 'VEC_UNKNOWN_FUNC' to have
    // the 'Expected output' supplied as part of this question
    
    print_vector("VEC_UNKNOWN_FUNC", vec_unknown_func);
}

预期输出

VEC_A
0, 2
1, 2
2, 2
3, 2
VEC_B
2, 3
3, 3
VEC_SET_UNION
0, 2
1, 2
2, 2
3, 2
VEC_UNKNOWN_FUNC
0, 2
1, 2
2, 11
3, 11

感谢您抽出宝贵时间,请告诉我是否可以进一步澄清。

C++ STL C++14 标准

评论

2赞 Useless 6/23/2021
因此,编写一个将 ur 作为另一个参数的函数。问题是什么?set_union_transformmerge_duplicate
0赞 acegene 6/23/2021
你是说没有简单的方法来直接和专门使用标准库来处理这种情况吗?
0赞 Caleth 6/23/2021
@acegene是的,我们是这么说的。 它并不承诺拥有所有可能的算法,但它确实有一些有用的构建块。std
0赞 AndyG 6/23/2021
将两个等效元素合并到一个新元素中的二元函子需要有一些很好的前提条件,因为它很有可能使结果向量中的排序后置条件无效
0赞 acegene 6/23/2021
@AndyG点好。如果不考虑,很容易引起头痛。

答:

1赞 Caleth 6/23/2021 #1

正如@Useless在评论中建议的那样,要在 上做额外的事情,你应该根据该算法写一些东西。<algorithm>

改编自可能的实施

template<class InputIt1, class InputIt2,
         class OutputIt, class Compare,
         class BinaryOp>
OutputIt set_union_transform(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, InputIt2 last2,
                   OutputIt d_first, Compare comp,
                   BinaryOp binary_op)
{
    for (; first1 != last1; ++d_first) {
        if (first2 == last2)
            return std::copy(first1, last1, d_first);
        if (comp(*first2, *first1)) {
            *d_first = *first2++;
        } else if (comp(*first1, *first2)) {
            *d_first = *first1++;
        } else {
            *d_first = binary_op(*first1++, *first2++);
        }
    }
    return std::copy(first2, last2, d_first);
}

评论

0赞 acegene 6/23/2021
感谢您对如何调整内容以用于自定义用途的帮助:)<algorithm>
1赞 Daniel Dearlove 6/23/2021 #2

只是抨击键盘,但我认为你想要这样的东西:

std::vector<CustomStruct> vec_set_intersection1;
std::vector<CustomStruct> vec_set_intersection2;

// Find the duplicate objects in the first vector
std::set_intersection(vec_a.begin(), vec_a.end(),
    vec_b.begin(), vec_b.end(),           
    std::back_inserter(vec_set_intersection1),
    compare);

// Find the duplicate objects in the second vector
std::set_intersection(vec_b.begin(), vec_b.end(),
    vec_a.begin(), vec_a.end(),           
    std::back_inserter(vec_set_intersection2),
    compare);

// Apply the transformation
std::transform(vec_set_intersection1.begin(), vec_set_intersection1.end(),
    vec_set_intersection2.begin(), vec_set_intersection2.end(),
    std::back_inserter(vec_unknown_func),
    merge_duplicate);

评论

0赞 acegene 6/23/2021
据我了解,这将正确转换交集,但不包括每个向量独有的元素。但是,有趣的是,这如何颠倒传递给每个set_intersection调用的参数的顺序。这允许从每个向量中提取值,这些值是交集的一部分,以便在转换调用中使用,很酷!