简体   繁体   English

合并两个std :: sets

[英]Merge two std::sets

I need to merge two sets into a resultant set on basis of one member variable qty if the prices are same. 如果价格相同,我需要根据一个成员变量qty将两个集合合并为结果集合。 In the below example my resultant set s3 should contain: 在下面的示例中,我的结果集s3应该包含:

Price : 100 Qty : 40 价格:100数量:40

Price : 200 Qty : 60 价格:200数量:60

Please note qty above is a sum of qty in both the sets respective when the price is same. 请注意,上述数量是当价格相同时两组中的数量之和。

My question is how do I construct the set s3 below: 我的问题是如何构造下面的set s3:

Please guide me with the same. 请同样指导我。

#include <set>
#include <iostream>

using namespace std;

class PriceLevel
{
public:
    int price;
    int qty;

    PriceLevel(int _price, int _qty)
    {
        price = _price;
        qty = _qty;
    }

    friend bool operator<(const PriceLevel &p, const PriceLevel &q);
};

bool operator<(const PriceLevel &p, const PriceLevel &q)
{
    if(p.price < q.price)
    {
        return true;
    }
    else
    {
        return false;
    }
}

int main()
{
    std::set<PriceLevel> s1;
    std::set<PriceLevel> s2;

    PriceLevel p1(100,10);
    PriceLevel p2(200,20);

    PriceLevel p3(100,30);
    PriceLevel p4(200,40);

    s1.insert(p1);
    s1.insert(p2);

    s2.insert(p3);
    s2.insert(p4);

    std::set<PriceLevel> s3;

    set<PriceLevel>::iterator it = s3.begin();

    // How should I Initialize s3

    for(; it != s3.end(); it++)
    {
        cout << "Price: " << it->price << endl;
        cout << "Qty : " << it->qty << endl;
    }
}

If you are absolutely sure that both source sets contain exactly the same prices, you can use the binary version of std::transform . 如果您完全确定两个源集包含的价格完全相同,则可以使用std::transform的二进制版本。

If they might contain unequal data, you'll have to do it manually, like this: 如果它们可能包含不相等的数据,则必须手动进行操作,如下所示:

std::set<PriceLevel> s3;

// How should I Initialize s3
std::set<PriceLevel>::iterator 
    first1 = s1.begin(),
    last1 = s1.end(),
    first2 = s2.begin(),
    last2 = s2.end();
while (first1 != last1 && first2 != last2) {
    if (first1->price < first2->price) {        
        s3.insert(*first1++);
    }
    else if (first1->price > first2->price) {
        s3.insert(*first2++);
    }
    else {
        s3.insert(PriceLevel(first1->price, first1->qty + first2->qty));
        ++first1;
        ++first2;
    }
}
while (first1 != last1) {
     s3.insert(*first1++);
}
while (first2 != last2) {
     s3.insert(*first2++);
}

This is best put in an extra function. 最好将它放在一个附加功能中。

View on IdeOne 在IdeOne上查看

If you only need those prices in the result set which existed in both source sets, it is a bit simpler: 如果您需要两个源集中存在的结果集中的价格,则要简单一些:

while (first1 != last1 && first2 != last2) {
    if (first1->price < first2->price) {        
        ++first1;
    }
    else if (first1->price > first2->price) {
        ++first2;
    }
    else {
        s3.insert(PriceLevel(first1->price, first1->qty + first2->qty));
        ++first1;
        ++first2;
    }
}

set is not an appropriate data structure for your application here. set不是适合您的应用程序的数据结构。 Consider using a map<int, int> instead: 考虑使用map<int, int>代替:

map<int, int> p1, p2, p3; // map price -> quantity

p1[100] = 10;
p1[200] = 20;

p2[100] = 30;
p2[200] = 40;

p3 = p1;
for(auto &i : p2) {
    p3[i.first] += i.second;
}

// Now p3[100]=40 and p3[200]=60.

You can also use a set kind of like a map using set::find : 您也可以使用set有点像一个map使用set::find

s3 = s1;
for(auto &i : s2) {
    auto it = s3.find(i);
    if(it == s3.end()) {
        s3.insert(i);
    } else {
        it->qty += i.qty;
    }
}

For this to work, you will have to declare qty as a mutable int , so that it can be modified even if the PriceLevel struct is const (since elements of a set are const ). 为此,必须将qty声明为mutable int ,以便即使PriceLevel结构为const (因为set元素为const ),也可以对其进行修改。

If you can't make the variable mutable , then you can try removing the existing set element and then adding a new, merged element. 如果不能使变量mutable ,则可以尝试删除现有的set元素,然后添加一个新的合并元素。

You are essentially trying to use a set as a map AND merge values with equal keys. 本质上,您试图将集合用作映射并使用相等的键合并值。 You will need to roll your own result (not to mention that it really isn't advisable...). 您需要滚动自己的结果(更不用说它确实不建议...)。 Here is something to get you started. 这是一些让您入门的东西。

#include <iostream>
#include <set>

using namespace std;

class PriceLevel
{
public:
    int price;
    int qty;

    PriceLevel() {
        price = 0;
        qty = 0;
    }

    PriceLevel(int _price, int _qty)
    {
        price = _price;
        qty = _qty;
    }

    friend bool operator<(const PriceLevel &p, const PriceLevel &q);

    //Compares two PriceLevel objects and merges their values if their keys are the same.
    //Return value is a std::pair that
    //denotes if the compare was successful and the result is meaningful.        
    static std::pair<bool, PriceLevel> merge_equal(const PriceLevel& p, const PriceLevel& q) {
        std::pair<bool, PriceLevel> result;
        result.first = false;
        if(p.price == q.price) {
            result.first = true;
            result.second.price = p.price;
            result.second.qty = p.qty + q.qty;
        }
        return result;
    }

};

bool operator<(const PriceLevel &p, const PriceLevel &q)
{
    if(p.price < q.price)
    {
        return true;
    }
    else
    {
        return false;
    }
}

int main()
{
    std::set<PriceLevel> s1;
    std::set<PriceLevel> s2;

    PriceLevel p1(100,10);
    PriceLevel p2(200,20);

    PriceLevel p3(100,30);
    PriceLevel p4(200,40);

    s1.insert(p1);
    s1.insert(p2);

    s2.insert(p3);
    s2.insert(p4);

    std::set<PriceLevel> s3;

    //Just in case...the world may explode otherwise.
    if(s1.size() == s2.size()) {

        for(const auto& pl1 : s1) {
            for(const auto& pl2 : s2) {
                //Only insert valid values.
                auto r = PriceLevel::merge_equal(pl1, pl2);
                if(r.first) s3.insert(r.second);
            }
        }

        for(auto it = s3.begin(); it != s3.end(); it++) {
            cout << "Price: " << it->price << endl;
            cout << "Qty : " << it->qty << endl;
        }
    }
}

You can merge two sets with just two lines 您只需两行就可以合并两个集合

#include <set>

template <typename _Ty>
std::set<_Ty> merge(const std::set<_Ty> &x, const std::set<_Ty> &y) const
{
    std::set<_Ty> merged = x; //initial merged set from x
    merged.insert(y.begin(), y.end()); //add contents of y to merged

    return move(merged);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM