View difference between Paste ID: yLhQ6RvR and B8KnzVwP
SHOW: | | - or go back to the newest paste.
1
-----------------------------------------------------------------------
2
main.cpp
3
-----------------------------------------------------------------------
4
#include <algorithm>
5
#include <cassert>
6
#include <iostream>
7
#include <numeric>
8
#include <vector>
9
10
#include "xml.h"
11
12
using namespace std;
13
14
struct Spending {
15
    string category;
16
    int amount;
17
};
18
19
int CalculateTotalSpendings(const vector<Spending>& spendings) {
20
    return accumulate(spendings.begin(), spendings.end(), 0,
21
                      [](int current, const Spending& spending) {
22
                          return current + spending.amount;
23
                      });
24
}
25
26
string FindMostExpensiveCategory(const vector<Spending>& spendings) {
27
    assert(!spendings.empty());
28
    auto compare_by_amount = [](const Spending& lhs, const Spending& rhs) {
29
        return lhs.amount < rhs.amount;
30
    };
31
    return max_element(begin(spendings), end(spendings), compare_by_amount)->category;
32
}
33
34
vector<Spending> LoadFromXml(istream& input) {
35
    std::vector<Spending> result;
36
    
37
    auto tags = Load(input).GetRoot().Children();
38
    
39
    for (auto tag : tags) {
40
        Spending helper;
41
        
42
        helper.amount = tag.AttributeValue<int>("amount");
43
        helper.category = tag.AttributeValue<string>("category");
44
        
45
        result.push_back(move(helper));
46
    }
47
    return result;
48
}
49
50
int main() {
51
    const vector<Spending> spendings = LoadFromXml(cin);
52
    cout << "Total "sv << CalculateTotalSpendings(spendings) << '\n';
53
    cout << "Most expensive is "sv << FindMostExpensiveCategory(spendings) << '\n';
54
}
55
-----------------------------------------------------------------------
56
xml.h
57
-----------------------------------------------------------------------
58
#pragma once
59
60
#include <istream>
61
#include <sstream>
62
#include <string>
63
#include <string_view>
64
#include <unordered_map>
65
#include <vector>
66
67
class Node {
68
public:
69
    Node(std::string name, std::unordered_map<std::string, std::string> attrs);
70
71
    const std::vector<Node>& Children() const;
72
    void AddChild(Node node);
73
    std::string_view Name() const;
74
75
    template <typename T>
76
    T AttributeValue(const std::string& name) const;
77
78
private:
79
    std::string name_;
80
    std::vector<Node> children_;
81
    std::unordered_map<std::string, std::string> attrs_;
82
};
83
84
class Document {
85
public:
86
    explicit Document(Node root);
87
88
    const Node& GetRoot() const;
89
90
private:
91
    Node root_;
92
};
93
94
Document Load(std::istream& input);
95
96
template <typename T>
97
inline T Node::AttributeValue(const std::string& name) const {
98
    std::istringstream attr_input(attrs_.at(name));
99
    T result;
100
    attr_input >> result;
101
    return result;
102
}
103
-----------------------------------------------------------------------
104
xml.cpp
105
-----------------------------------------------------------------------
106
#include "xml.h"
107
108
using namespace std;
109
110
pair<string_view, string_view> Split(string_view line, char by) {
111
    size_t pos = line.find(by);
112
    string_view left = line.substr(0, pos);
113
114
    if (pos < line.size() && pos + 1 < line.size()) {
115
        return {left, line.substr(pos + 1)};
116
    } else {
117
        return {left, string_view()};
118
    }
119
}
120
121
string_view Lstrip(string_view line) {
122
    while (!line.empty() && isspace(line[0])) {
123
        line.remove_prefix(1);
124
    }
125
    return line;
126
}
127
128
string_view Unquote(string_view value) {
129
    if (!value.empty() && value.front() == '"') {
130
        value.remove_prefix(1);
131
    }
132
    if (!value.empty() && value.back() == '"') {
133
        value.remove_suffix(1);
134
    }
135
    return value;
136
}
137
138
Node LoadNode(istream& input) {
139
    string root_name;
140
    getline(input, root_name);
141
142
    Node root(root_name.substr(1, root_name.size() - 2), {});
143
    for (string line; getline(input, line) && line[1] != '/';) {
144
        auto [node_name, attrs] = Split(Lstrip(line), ' ');
145
        attrs = Split(attrs, '>').first;
146
        unordered_map<string, string> node_attrs;
147
        while (!attrs.empty()) {
148
            const auto [head, tail] = Split(attrs, ' ');
149
            const auto [name, value] = Split(head, '=');
150
            if (!name.empty() && !value.empty()) {
151
                node_attrs[string(Unquote(name))] = string(Unquote(value));
152
            }
153
            attrs = tail;
154
        }
155
156
        root.AddChild(Node(string(node_name.substr(1)), move(node_attrs)));
157
    }
158
    return root;
159
}
160
161
Document Load(istream& input) {
162
    return Document{LoadNode(input)};
163
}
164
165
Node::Node(string name, unordered_map<string, string> attrs)
166
    : name_(move(name))
167
    , attrs_(move(attrs)) {
168
}
169
170
const vector<Node>& Node::Children() const {
171
    return children_;
172
}
173
174
Document::Document(Node root)
175
    : root_(move(root)) {
176
}
177
178
const Node& Document::GetRoot() const {
179
    return root_;
180
}
181
182
void Node::AddChild(Node node) {
183
    children_.push_back(move(node));
184
}
185
186
string_view Node::Name() const {
187
    return name_;
188
}