How to add elements in vector together based on in

2020-05-09 21:58发布

问题:

I have two vector structs, one contains the codes and cost for each, and another is just orders that contains requested codes and totalCost (to be calculated)

vector parts(codes, cost);

vector orders(codes, totalCost); //totalCost set to 0;

where the parts vector contains something like ('A', 10, 'B', 20);

Where A and B are parts, 10 is cost for A, 20 cost for B.

and the orders vector contains orders such as A,B,C or just A,B Say we receive an order of parts A and B.

how do we go about adding these two based on cost from parts and storing the result in a new int that we gonna use later to add to the vector struct orders (totalCost).

I was trying for several hours, I think I need to use std::transform and maybe std::accumulate? just not sure how to put the two together...

This is what I have written so far:

int totalCost;
for(auto i : customers){
    for(auto x : parts){
      totalCost = accumulate(i.partsList.begin(), i.partsList.end(), ???);
      //then need to store cost for each order for use later
}

I have also tried:

void test(){
    int cost;
    for(unsigned i =0; i < customers.size(); i++){
        for(unsigned x=0; x < partsVec.size(); x++){
            for(unsigned z=0; z < customers.at(i).partsList.size(); z++){

                if(partsVec.at(x).code == customers.at(i).partsList.at(z)){
                    cost += partsVec.at(x).cost;
                    customers.at(i).cost= cost;
                }
            }
        }
    }
      for(auto i : customers){
        cout << i.cost<< endl;
    }
}

This output this:

40 //this is correct.

80 //this is incorrect, needs to be 40 as both customers have ordered same parts!

As you can see, this keeps incriminating and I can't figure out a way to stop it.

what I am trying to do, is get the total cost of all parts in partsList based on info from the parts vector. Customers vector has another vector of chars in it called partsList, then I can change the totalCost of each order to value obtained from above using accumulate or some other algorithm

回答1:

Try something like this:

struct Part
{
    char code;
    double cost;

    Part(char code, double cost)
        : code(code), cost(cost)
    {
    }
};

std::vector<Part> parts;

double costOfPart(char code)
{
    for(const Part &part : parts)
    {
        if (part.code == code)
            return part.cost;
    }
    return 0.0;
}

struct OrderItem
{
    char partCode;
    size_t quantity;

    OrderItem(char partCode, size_t quantity)
        : partCode(partCode), quantity(quantity)
    {
    }
};

struct Order
{
    int code;
    std::vector<OrderItem> items;

    Order(int code)
       : code(code)
    {
    }

    void addItem(char partCode, size_t quantity)
    {
        for (OrderItem &item : items)
        {
            if (item.partCode == partCode)
            {
                item.quantity += quantity;
                return;
            }
        }
        items.push_back(OrderItem(partCode, quantity));
    }

    double totalCost() const
    {
        double total = 0.0;
        for (const OrderItem &item : items)
        {
            total += (costOfPart(item.partCode) * item.quantity);
        }
        // TOOD: fees, taxes, discounts, etc...
        return total;
    }
};

std::vector<Order> orders;

double costOfAllOrders()
{
    double total = 0.0;
    for(const Order &order : orders)
    {
        total += order.totalCost();
    }
    return total;
}

double costOfOrder(int orderCode)
{
    for(const Order &order : orders)
    {
        if (order.code == orderCode)
            return order.totalCost();
    }
    return 0.0;
}

...

parts.push_back(Part('A', 10.0));
parts.push_back(Part('B', 20.0));

...

Order order(12345);
order.addItem('A', 1);
orders.push_back(order);

...

double costOfOneOrder = costOfOrder(12345);
double totalCostOfOrders = costOfAllOrders();
...

Or, if you really want to use std::accumulate(), then you can do something like this:

#include <algorithm>
#include <numeric>

struct Part
{
    char code;
    double cost;

    Part(char code, double cost)
        : code(code), cost(cost)
    {
    }
};

std::vector<Part> parts;

double costOfPart(char code)
{
    auto iter = std::find_if(parts.begin(), parts.end(),
        [=](Part &part){ return part.code == code; }
    );
    if (iter != parts.end())
        return iter->cost;
    return 0.0;
}

struct OrderItem
{
    char partCode;
    size_t quantity;

    OrderItem(char partCode, size_t quantity)
        : partCode(partCode), quantity(quantity)
    {
    }
};

struct Order
{
    int code;
    std::vector<OrderItem> items;

    Order(int code)
       : code(code)
    {
    }

    void addItem(char partCode, size_t quantity)
    {
        auto iter = std::find_if(items.begin(), items.end(),
            [=](OrderItem &item){ return item.partCode == partCode; }
        );
        if (iter != items.end())
            iter->quantity += quantity;
        else
            items.emplace_back(partCode, quantity);
    }

    double totalCost() const
    {
        double total = std::accumulate(items.begin(), items.end(), 0.0,
            [](double totalSoFar, const OrderItem &item) {
                return totalSoFar + (costOfPart(item.partCode) * item.quantity);
            }
        );
        // TOOD: fees, taxes, discounts, etc...
        return total;
    }
};

std::vector<Order> orders;

double costOfAllOrders()
{
    return std::accumulate(orders.begin(), orders.end(), 0.0,
        [](double totalSoFar, const Order &order){
            return totalSoFar + order.totalCost();
        }
    );
}

double costOfOrder(int orderCode)
{
    auto iter = std::find_if(orders.begin(), orders.end(),
        [=](Order &order){ return order.code == orderCode; }
    );
    if (iter != orders.end())
        return iter->totalCost();
    return 0.0;
}

...

parts.emplace_back('A', 10.0);
parts.emplace_back('B', 20.0);

...

Order order(12345);
order.addItem('A', 1);
orders.push_back(order);

...

double costOfOneOrder = costOfOrder(12345);
double totalCostOfOrders = costOfAllOrders();
...

Update: Based on the code you have added, you are looping all wrong. You need something more like this instead:

auto partCost = [&](char code) -> int {
    for(auto &p : partsVec) {
        if (p.code == code)
            return p.cost;
    }
    return 0;
}

int totalCost = 0;
for(auto &c : customers){
    totalCost += accumulate(c.partsList.begin(), c.partsList.end(), 0,
        [&](int totalSoFar, char code) {
            return totalSoFar + partCost(code);
        }
    );
}

Or, just using plain loops:

void test(){
    int cost = 0;
    for(unsigned i = 0; i < customers.size(); i++) {
        auto &c = customers[i];
        for(unsigned x = 0; x < c.partsList.size(); x++) {
            auto partCode = c.partsList[x];
            for(unsigned z = 0; z < partsVec.size(); z++) {
                auto &p = partsVec[z];
                if (p.code == partCode) {
                    cost += p.cost;
                    break;
                }
            }
        }
    }
    cout << cost << endl;
}


回答2:

Just find for every part in order it's cost from the parts container, that you pass to lambda in accumulate algorithm. I assume, that either order behaves as a container or each part in order can be obtained and put to a vector.

std::accumulate(order.begin(), order.end(), 0, [&parts](const auto & o) {
    return std::find(parts.begin(), parts.end(), o).cost();
}

You may also try and write a "nasty" function object that will behave as a lambda.

class AccumulatorHelper {
public:
    vector<Parts>& parts;
    AccumulatorHelper(vector<Parts>& p): parts(p) { }
    int operator()(const Order& order) {
        return std::find(parts.begin(), parts.end(), order.character());
    }
};