简体   繁体   中英

merge std::set on one member variable

My requirement here is to merge the qty of both the sets if the price is same but isImplied bool are different.

Current Output:

Price : 100 IsImplied : 0 Qty :10

Price : 200 IsImplied : 0 Qty : 20

As the price 100 and 200 were already present in the set the insertion of p3 and p4 is ignored.

Desired output:

Price : 100 IsImplied : 0 Qty :40 (10 + 30) (Qty is merged as P1 and P3 have same price but different isImplied values)

Price : 200 IsImplied : 0 Qty : 60 (20 + 40) (Qty is merged as P2 and P4 have same price but different isImplied values)

class PriceLevel
{
public:
    int price;
    int qty;
    bool isImplied;

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

    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;

    PriceLevel p1(100,10, false);
    PriceLevel p2(200,20, false);
    PriceLevel p3(100,30, true);
    PriceLevel p4(200,40, true);

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

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

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

        cout << "Qty : " << it->qty << endl;

        cout << "IsImplied: " << it->isImplied << endl;

    }
}

If you need to retain the quantity as well, your compare function should use that information. set comparison works on strict weak ordering. There are two ways to achieve this. Pick the one that fits your design best.

1.Instead of keeping a set of PriceLevel itself, keep a map with the key as the Price and value as the quantity. Your update function will look something like:

void update(map<int, int> &valueMap, const PriceList &val)
{
    valueMap[val.price] += val.qty;    
}

` 2. Modify the insertion logic in your set. Update would look something like:

void update(set<PriceList> &valueMap, PriceList val)
{
    auto iter = valueMap.find(val);
    if (iter != valueMap.end())
    {
        val.qty = iter->qty + val.qty;
        valueMap.erase(iter);
    }
    valueMap.insert(val);
}

and obviously your compare function needs to be updated to account for qty. It should look something like

bool comp(const PriceList& val1, const PriceList& val2)
{
    return make_pair(val1.price, val1.qty) < make_pair(val2.price, val2.qty);
}

You want to do something like like the following. Note we only do a single lookup.

// attempt to insert
std::pair<bool, std::set<PriceLevel>::iterator> result = s1.insert(p1);
if (result.first)  // insert did not work since element already existed
{
    PriceLevel & temp = *(result.second);
    if (temp.isImplied != p1.isImplied)
    {
        temp.qty += p1.qty;  // sum
    }
    else
    {
        temp.qty = p1.qty;  // overwrite
    }
}
// otherwise p1 didn't exist and was inserted

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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