Related
I wanted to create a Json-file that will be created from the data received earlier. I don't understand how to work with Json files at all. I want to use the Boost library, because I am using it in another part of this program. I need to create a Json-file with a specific structure which I have attached below.
I need to get JSON:
{
"track": {
"Wheels": {
"Wheel": [
{
"start_pos": "10",
"end_pos": "25"
},
{
"start_pos": "22",
"end_pos": "78"
}
]
},
"Brakes": {
"Brake": [
{
"start_pos": "10",
"midl_pos": "25"
}
]
}
}
}
C++:
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/json_parser.hpp"
#include <string>
using namespace std;
using boost::property_tree::ptree;
struct wheel
{
string start_pos;
string end_pos;
};
struct brake
{
string start_pos;
string midl_pos;
};
int main()
{
string tr = "track";
string ws = "Wheels";
string bs = "Brakes";
struct wheel w1;
w1.start_pos = "10";
w1.end_pos = "25";
struct wheel w2;
w2.start_pos = "22";
w2.end_pos = "78";
struct brake b1;
b1.start_pos = "10";
b1.midl_pos = "25";
return 0;
}
Implementing it with the Boost JSON customization points.
Doing it test-driven:
Live On Coliru
#include "boost/json/src.hpp" // header-only approach
#include <iostream>
namespace json = boost::json;
using json::value_from;
using json::value_to;
static const json::value expected = json::parse(R"({
"track": {
"Wheels": {
"Wheel": [
{
"start_pos": "10",
"end_pos": "25"
},
{
"start_pos": "22",
"end_pos": "78"
}
]
},
"Brakes": {
"Brake": [
{
"start_pos": "10",
"midl_pos": "25"
}
]
}
}
})");
namespace MyLib {
struct wheel { int start_pos, end_pos; };
struct brake { int start_pos, midl_pos; };
struct track {
std::vector<wheel> wheels;
std::vector<brake> brakes;
};
void tag_invoke(json::value_from_tag, json::value& jv, wheel const& w) {
jv = {
{"start_pos", std::to_string(w.start_pos)},
{"end_pos", std::to_string(w.end_pos)},
};
}
void tag_invoke(json::value_from_tag, json::value& jv, brake const& b) {
jv = {
{"start_pos", std::to_string(b.start_pos)},
{"midl_pos", std::to_string(b.midl_pos)},
};
}
void tag_invoke(json::value_from_tag, json::value& jv, track const& t) {
jv = {{"track",
{
{"Wheels", {{"Wheel", t.wheels}}},
{"Brakes", {{"Brake", t.brakes}}},
}}};
}
}
int main()
{
MyLib::track track{{
{10, 25},
{22, 78},
},
{
{10, 25},
}};
json::value output = json::value_from(track);
std::cout << output << "\n";
std::cout << expected << "\n";
std::cout << "matching: " << std::boolalpha << (output == expected) << "\n";
}
Prints
{"track":{"Wheels":{"Wheel":[{"start_pos":"10","end_pos":"25"},{"start_pos":"22","end_pos":"78"}]},"Brakes":{"Brake":[{"start_pos":"10","midl_pos":"25"}]}}}
{"track":{"Wheels":{"Wheel":[{"start_pos":"10","end_pos":"25"},{"start_pos":"22","end_pos":"78"}]},"Brakes":{"Brake":[{"start_pos":"10","midl_pos":"25"}]}}}
matching: true
BONUS
Adding full round-trip support. I elected to remove the to_string as it looks like it may have been a requirement from the Boost Property Tree limitations only:
Live On Coliru
#include "boost/json/src.hpp" // header-only approach
#include <iostream>
namespace json = boost::json;
using json::value_from;
using json::value_to;
namespace MyLib {
struct wheel {
int start_pos, end_pos;
bool operator==(wheel const&) const = default;
};
struct brake {
int start_pos, midl_pos;
bool operator==(brake const&) const = default;
};
struct track {
std::vector<wheel> wheels;
std::vector<brake> brakes;
bool operator==(track const&) const = default;
};
void tag_invoke(json::value_from_tag, json::value& jv, wheel const& w) {
jv = {{"start_pos", w.start_pos}, {"end_pos", w.end_pos}};
}
void tag_invoke(json::value_from_tag, json::value& jv, brake const& b) {
jv = {{"start_pos", b.start_pos}, {"midl_pos", b.midl_pos}};
}
void tag_invoke(json::value_from_tag, json::value& jv, track const& t) {
jv = {{"track",
{
{"Wheels", {{"Wheel", t.wheels}}},
{"Brakes", {{"Brake", t.brakes}}},
}}};
}
wheel tag_invoke(json::value_to_tag<wheel>, json::value const& jv) {
return {
value_to<int>(jv.at("start_pos")),
value_to<int>(jv.at("end_pos")),
};
}
brake tag_invoke(json::value_to_tag<brake>, json::value const& jv) {
return {
value_to<int>(jv.at("start_pos")),
value_to<int>(jv.at("midl_pos")),
};
}
track tag_invoke(json::value_to_tag<track>, json::value const& jv) {
auto& track = jv.at("track");
return {
value_to<decltype(track::wheels)>(track.at("Wheels").at("Wheel")),
value_to<decltype(track::brakes)>(track.at("Brakes").at("Brake")),
};
}
}
int main()
{
MyLib::track const track{{
{110, 125},
{111, 126},
{142, 198},
},
{
{10, 25},
{120, 135},
}};
json::value output = json::value_from(track);
std::cout << output << "\n";
std::cout << "Roundtrip: " << std::boolalpha
<< (value_to<MyLib::track>(output) == track) << "\n";
}
Prints
{"track":{"Wheels":{"Wheel":[{"start_pos":110,"end_pos":125},{"start_pos":111,"end_pos":126},{"start_pos":142,"end_pos":198}]},"Brakes":{"Brake":[{"start_pos":10,"midl_pos":25},{"start_pos":120,"midl_pos":135}]}}}
Roundtrip: true
Despite comments suggesting to use a different library, which they could, I think #Nindzzya wanted to specifically use the boost library.
Using the boost library from How to use boost::property_tree to load and write JSON:
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/json_parser.hpp"
#include <string>
#include <iostream>
using namespace std;
namespace pt = boost::property_tree;
struct wheel
{
string start_pos;
string end_pos;
};
struct brake
{
string start_pos;
string midl_pos;
};
int main()
{
string tr = "track";
string ws = "Wheels";
string bs = "Brakes";
struct wheel w1;
w1.start_pos = "10";
w1.end_pos = "25";
struct wheel w2;
w2.start_pos = "22";
w2.end_pos = "78";
struct brake b1;
b1.start_pos = "10";
b1.midl_pos = "25";
pt::ptree wheel1, wheel2, wheels, wheel;
pt::ptree brake1, brakes, brake;
pt::ptree track, root;
wheel1.put("start_pos", w1.start_pos);
wheel1.put("end_pos", w1.end_pos);
wheel2.put("start_pos", w2.start_pos);
wheel2.put("end_pos", w2.end_pos);
wheels.push_back(make_pair("", wheel1));
wheels.push_back(make_pair("", wheel2));
wheel.add_child("Wheel", wheels);
track.add_child(ws, wheel);
brake1.put("start_pos", b1.start_pos);
brake1.put("midl_pos", b1.midl_pos);
brakes.push_back(make_pair("", brake1));
brake.add_child("Brake", brakes);
track.add_child(bs, brake);
root.add_child(tr, track);
pt::write_json(std::cout, root);
return 0;
}
results in:
{
"track": {
"Wheels": {
"Wheel": [
{
"start_pos": "10",
"end_pos": "25"
},
{
"start_pos": "22",
"end_pos": "78"
}
]
},
"Brakes": {
"Brake": [
{
"start_pos": "10",
"midl_pos": "25"
}
]
}
}
}
Here is the code I have, I am having trouble finding a way to remove all Apple elem in the array. I am able to count the apples in the array. I hope someone can help...
string items[10] = { "Apple", "Oranges", "Pears", "Apple", "bananas", "Apple", "Cucumbers", "Apple", "Lemons", "Apple" };
//Counts the total amount of apples
int n = sizeof(items) / sizeof(items[0]);
cout << "Number of times Apple appears : "
<< count(items, items + n, "Apple");
//remove the element Apple from array
if (string items[].contains("Apple"))
{
items[].remove("Apple");
}
Some options you'd have would be:
Walk your array of items and substitute your "Apple" strings for empty strings.
Use a std::vector of strings and whether a) initialize it with the array of items and then call std::erase_if (C++20) to remove the "Apple" strings, or b) initialize it without elements and then call std::copy_if together with std::back_inserter to append the non-"Apple" strings.
[Demo]
#include <algorithm> // copy_if, transform
#include <iostream> // cout
#include <string>
#include <vector> // erase_if
int main()
{
{
std::string items[10] = { "Apple", "Oranges", "Pears", "Apple", "bananas", "Apple", "Cucumbers", "Apple", "Lemons", "Apple" };
std::transform(std::begin(items), std::end(items), std::begin(items), [](auto& s) {
return (s == "Apple" ? "" : s);
});
for (const auto& s : items) { std::cout << s << ", "; }
std::cout << "\n";
}
{
const std::string items[10] = { "Apple", "Oranges", "Pears", "Apple", "bananas", "Apple", "Cucumbers", "Apple", "Lemons", "Apple" };
std::vector<std::string> v{std::cbegin(items), std::cend(items)};
std::erase_if(v, [](auto& s) { return s == "Apple"; });
for (const auto& s : v) { std::cout << s << ", "; }
std::cout << "\n";
}
{
const std::string items[10] = { "Apple", "Oranges", "Pears", "Apple", "bananas", "Apple", "Cucumbers", "Apple", "Lemons", "Apple" };
std::vector<std::string> v{};
std::copy_if(std::cbegin(items), std::cend(items), std::back_inserter(v), [](auto& s) {
return s != "Apple";
});
for (const auto& s : v) { std::cout << s << ", "; }
}
}
// Outputs:
//
// , Oranges, Pears, , bananas, , Cucumbers, , Lemons, ,
// Oranges, Pears, bananas, Cucumbers, Lemons,
// Oranges, Pears, bananas, Cucumbers, Lemons,
The simplest and most efficient way to remove a number of elements in an array is to create a new array:
#include <iostream>
using namespace std;
int main()
{
string items[10] = { "Apple", "Oranges", "Pears", "Apple", "bananas", "Apple", "Cucumbers", "Apple", "Lemons", "Apple" };
string new_items[10];
int new_size = 0;
// construct new array
for (int i = 0; i < sizeof(items)/sizeof(string); i++) {
if ("Apple" != items[i]) {
new_items[new_size++] = items[i];
}
}
// print new array
for (int i = 0; i < new_size; i++) {
cout << new_items[i] << " ";
}
cout << endl;
return 0;
}
std::map<int, std::vector<int>> tmp_map = { { 1, [10,5,4] }, { 2, [5,5,1] },
{ 3, [2,4,3] }, { 4, [9,7,8] } };
I want to order this map by the 3rd value in vector value.
So the outcome will be like :
{ { 2, [5,5,1] },{ 3, [2,4,3] },{ 1, [10,5,4] },{ 4, [9,7,8] } }
Standard approach . . .
Copy map to vector
Sort vector with custom comparator
#include <iostream>
#include <map>
#include <vector>
#include <utility>
#include <algorithm>
int main() {
std::map<int, std::vector<int>> tmp_map = { { 1,{10,5,4} }, { 2,{5,5,1} },
{ 3,{2,4,3} }, { 4,{9,7,8} } };
// For easier and shorter writing
using DataType = std::pair<int, std::vector<int>>;
// Create Vector with Elements from Map
std::vector<DataType> data(tmp_map.begin(), tmp_map.end());
// Sort data
std::sort(data.begin(), data.end(), [](const DataType& d1, const DataType& d2) { return d1.second[2] < d2.second[2]; });
// show result
for (const auto& [key, value] : data) {
std::cout << key << " --> ";
for (const int i : value) std::cout << i << " ";
std::cout << "\n";
}
return 0;
}
You're map is already sorted by its key value so you cannot reorder it inplace. What you should do instead is copy it into a vector and then sort it using a custom operator like this:
#include <map>
#include <vector>
#include <algorithm>
int main()
{
std::map<int, std::vector<int>> tmp_map = { { 1, {10,5,4} }, { 2, {5,5,1} },
{ 3, {2,4,3} }, { 4, {9,7,8} } };
//! Copy the map
using P = std::pair<int, std::vector<int>>;
std::vector<P> copy(tmp_map.begin(), tmp_map.end());
//! Sort it the way you want (here I'm sorting on based on the second element
//! of the array.
std::sort(copy.begin(), copy.end(), [](const P& a, const P& b)
{
return a.second[2] < b.second[2];
});
}
I have a data struct -
{"BRAZIL", { {"IPHONE",{100,100} },{"IPOD", {65,100} } }
I want to use operator = to save the data into a struct . I tried to design the struct like map<string, vector<map<string, vector<int>>>>,and use -
price_stock["BRAZIL"] = { { "IPHONE", { 100, 100 } }, { "IPOD", { 65, 100 } } }
But I failed to directly assign the data into struct.
You are missing a level of braces:
price_stock["BRAZIL"] = {
{ // first element in vector
{"IPHONE", {100, 100}} // element in inner map
},
{ // second element in vector
{"IPOD", {65, 100}} // element in inner map
}
};
Below I have given a simple example on how to use a struct in C++.
#include <iostream>
#include <string>
#include <map>
#include <vector>
struct prices {
std::string title;
int stock;
int price;
};
int main ()
{
std::map<std::string, std::vector<prices> > priceMap;
std::vector<prices> priceVec {{"IPHONE",100,100}, {"IPOD",65,100}};
priceMap["Brazil"] = priceVec;
for (auto& itemVector : priceMap) {
for (auto& structItem : itemVector.second) {
std::cout << structItem.title << ":" << structItem.price << std::endl;
}
}
}
Can I do something like this?
std::vector<std::vector<std::string>> vec;
vec.push_back(std::vector<std::string>("abc", "cde", "fgh", "ijk"));
vec.push_back(std::vector<std::string>("abc", "cde", "fgh", "ijk"));
vec.push_back(std::vector<std::string>("abc", "cde", "fgh", "ijk"));
I already know which values I want and I'm trying to create a 3 x 4 vector like this.
Edit: I would also prefer a C++03 solution since my compiler doesn't support C++11.
You need to use :
vec.push_back(std::vector<std::string>( { "abc", "cde", "fgh", "ijk" } ) ) ;
~~ ~~
I already know which values
Then why not this ? (C++11)
std::vector<std::vector<std::string>> vec
{
{ "abc", "cde", "fgh", "ijk" },
{ "abc", "cde", "fgh", "ijk" },
{ "abc", "cde", "fgh", "ijk" },
} ;
For repeating vectors of strings, you can use another constructor overload taking a count and the repeated element:
#include <iostream>
#include <string>
#include <vector>
int main ()
{
std::vector<std::vector<std::string>> vec
(
3, { "abc", "cde", "fgh", "ijk" }
);
for (v : vec) {
for (s : v)
std::cout << s << ",";
std::cout << "\n";
}
}
Live Example
You can have vector of vectors, but you initialize them wrongly. There is no constructor that accepts 4 parameters of type T. You can however make them an initialization list since c++11.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
std::vector<std::vector<std::string>> vec;
vec.push_back(std::vector<std::string>({"abc", "cde", "fgh", "ijk"}));
vec.push_back(std::vector<std::string>({"abc", "cde", "fgh", "ijk"}));
vec.push_back(std::vector<std::string>({"abc", "cde", "fgh", "ijk"}));
return 0;
}
Another one (even for prior to C++11):
int main() {
std::vector<std::vector<std::string> > vec;
std::string aa[] = {"abc", "cde", "fgh", "ijk"};
std::vector<std::string> vec1(aa, aa+sizeof(aa)/sizeof(std::string));
vec.push_back(vec1);
vec.push_back(vec1);
vec.push_back(vec1);
return 0;
}