C++ Design a struct of the data - c++

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;
}
}
}

Related

nlohmann::json array of objects conversion into memory structure

I am using the nlohmann JSON C++ library to read a JSON file with this structure:
{
"Main": [
{
"obj1": "bar"
},
{
"obj2": "foo"
}
]
}
The main object with key known to the user "Main" contains an array of objects with unknown key names.
I want to transfer the JSON object in the following program to a C++ structure. How could this be done?
#include <nlohmann/json.hpp>
#include <iostream>
#include <fstream>
using json = nlohmann::json;
int main()
{
std::ifstream ifs("../test/test_2.json");
json js = json::parse(ifs);
for (json::iterator it = js.begin(); it != js.end(); ++it)
{
std::cout << it.key() << " :\n";
std::cout << it.value() << "\n";
}
if (js.contains("Main"))
{
json a = js["Main"];
for (size_t idx = 0; idx < a.size(); ++idx)
{
json o = a.at(idx);
std::cout << o << "\n";
}
}
return 0;
}
Output:
Main :
[{"obj1":"bar"},{"obj2":"foo"}]
{"obj1":"bar"}
{"obj2":"foo"}
You could parse the vector of maps under Main with:
auto objects{ j.at("Main").get<objects_t>() };
Where:
using object_t = std::map<std::string, std::string>;
using objects_t = std::vector<object_t>;
[Demo]
#include <fmt/ranges.h>
#include <iostream> // cout
#include <map>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
using json = nlohmann::json;
using object_t = std::map<std::string, std::string>;
using objects_t = std::vector<object_t>;
int main() {
std::string str{R"({ "Main": [ { "obj1": "bar" }, { "obj2": "foo" } ] })"};
json j = json::parse(str);
auto objects{ j.at("Main").get<objects_t>() };
fmt::print("{}", objects);
}
// Outputs:
//
// [{"obj1": "bar"}, {"obj2": "foo"}]
Yes, but the API gives an automatic way to do this by means of NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE;
it seems it would be like just defining a vector like this, but this program gives the error
[json.exception.out_of_range.403] key 'key' not found
program
#include <nlohmann/json.hpp>
#include <iostream>
#include <fstream>
using json = nlohmann::json;
struct key_value_t
{
std::string key;
std::string value;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(key_value_t, key, value);
int main()
{
try
{
std::string str{ R"({ "Main": [ { "obj1": "bar" }, { "obj2": "foo" } ] })" };
json js = json::parse(str);
std::vector<key_value_t> kv;
if (js.contains("Main"))
{
js.at("Main").get_to(kv);
}
}
catch (std::exception& e)
{
std::cout << e.what() << '\n';
}
return 0;
}
This is one way to read and write the JSON in the original format, versions of the functions from_json() and to_json() are needed:
#include <iostream>
#include <fstream>
#include <map>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
using json = nlohmann::json;
struct key_value_t
{
std::string key;
std::string value;
};
void from_json(const json& j, key_value_t& kv)
{
assert(j.is_object());
assert(j.size() == 1);
kv.key = j.begin().key();
kv.value = j.begin().value();
}
void to_json(json& j, const key_value_t& kv)
{
j = nlohmann::json{
{kv.key, kv.value}
};
}
int main()
{
try
{
std::string str{ R"({ "Main": [ { "obj1": "bar" }, { "obj2": "foo" } ] })" };
json js_in = json::parse(str);
std::vector<key_value_t> kv_in;
//get input object
js_in.at("Main").get_to(kv_in);
if (js_in.contains("Main"))
{
nlohmann::json js_out = nlohmann::json::object_t();
std::vector<key_value_t> kv_;
key_value_t kv1{ "obj1", "1" };
key_value_t kv2{ "obj2", "2" };
kv_.push_back(kv1);
kv_.push_back(kv2);
nlohmann::json js_arr = kv_;
//add to main JSON object
js_out += {"Main", js_arr};
//save output
std::ofstream ofs("output.json");
ofs << std::setw(2) << js_out << std::endl;
ofs.close();
}
}
catch (std::exception& e)
{
std::cout << e.what() << '\n';
}
return 0;
}
Output is:
{
"Main": [
{
"obj1": "1"
},
{
"obj2": "2"
}
]
}

Overwriting first element of a vector changes contents of last element of vector

When writing my code, I noticed that running the code returns incorrect results, it turns out something in my code is changing the vector of handles for my coroutines and narrowed it down to one line of code where I overwrite an existing element of the handle vector with a new element.
Doing that also changes the content of the last element of the vector (more specifically, the bool from the myTask header) but not the elements in between.
Does anyone know what causes this? Any help appreciated.
Full implementation code:
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
#include <myTask.h>
#include <vector>
myTask<int> getVectorInt(std::vector<int>& array, int key, bool interleave)
{
std::cout << "started lookup of key: " << key << std::endl;
int result = array.at(key);
if (interleave == true)
{
std::cout << "about to suspend task with key: " << key << std::endl;
co_await std::suspend_always{};
std::cout << "resumed task with key: " << key << std::endl;
}
co_return result;
}
void interleavedExecution(std::vector<int>& lookup, std::vector<int>& keys, std::vector<int>& results)
{
// group size = number of concurrent instruction streams
int groupsize = 3;
// initialization of handle vector
std::vector<std::coroutine_handle<myTask<int>::promise_type>> handles;
// initialization of promise vector
std::vector<myTask<int>::promise_type> promises;
// creating/initializing first handles
for (int i = 0; i < groupsize; ++i)
{
handles.push_back(getVectorInt(lookup, keys.at(i), true));
}
int notDone = groupsize;
int i = groupsize;
// interleaved execution starts here
while (notDone > 0)
{
for (int handleIndex = 0; handleIndex < handles.size(); ++handleIndex)
{
if (!handles.at(handleIndex).promise().isDone())
{
handles.at(handleIndex).resume();
handles.at(handleIndex).promise().boolIsDone = true;
}
else
{
// pushing value back directly into results
results.push_back(handles.at(handleIndex).promise().value_);
if (i < keys.size())
{
// bug here, changes the last boolIsDone also to false (or messes with the last vector element)
handles.at(handleIndex) = getVectorInt(lookup, keys.at(i), true);
handles.at(handleIndex).promise().boolIsDone = false;
++i;
}
else { --notDone; }
}
}
}
}
template <typename T>
void outputVector(std::vector<T> toOutput)
{
std::cout << "Results: ";
for (int i = 0; i < toOutput.size(); ++i)
{
std::cout << toOutput.at(i) << ' ';
}
}
int main()
{
std::vector<int> lookup = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
std::vector<int> keys = {4, 2, 0, 6, 9, 0};
std::vector<int> results;
// correct output: 50, 30, 10, 70, 100, 10
// given output: 50, 30, 70, 10, 100, 10
interleavedExecution(lookup, keys, results);
outputVector(results);
}
myTask header carrying a bool:
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
template <typename T>
struct myTask {
struct promise_type {
unsigned value_;
~promise_type() {
//std::cout << "promise_type destroyed" << std::endl;
}
myTask<T> get_return_object() {
return myTask<T> {
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() { return {}; }
void unhandled_exception() { std::terminate(); }
std::suspend_always return_value(unsigned value) {
value_ = value;
return {};
}
bool boolIsDone = false;
auto isDone() { return boolIsDone; }
};
std::coroutine_handle<promise_type> h_;
operator std::coroutine_handle<promise_type>() const {
//std::cout << "called handle" << std::endl;
return h_; }
};
It turned out that changing the return type of final_suspend() from std::suspend_never to std::suspend_always fixed the issue.

how to order map by vector value c++

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];
});
}

Generating a map of strings to std::list of pointers in c++

I am trying to achieve the creation of such a map. The following code attempts to do this
#include <list>
#include <map>
#include <string>
class IntWithString {
private:
int a;
std::string s;
public:
IntWithString(int a, std::string s) : a(a), s(s) {}
std::string getString() { return s; }
int getInt() { return a; }
};
namespace {
std::map<std::string, std::list<IntWithString *> > m;
}
void appendMap(IntWithString *a) {
auto it = m.find(a->getString());
if (it != m.end()) {
m[a->getString()].push_back(a);
} else {
std::list<IntWithString *> l;
l.push_back(a);
m[a->getString()] = l;
}
}
int main() {
IntWithString a(10, "ten");
IntWithString b(11, "ten");
appendMap(&a);
appendMap(&b);
return 0;
}
However when looking at the map m with the debugger I am getting a map that maps "ten" to a list of size 0. What I would like is a list of size 2.
I am not sure what you mean. If I do:
std::cout << m.size() << ", " << m["ten"].size() << std::endl;
I get this output:
1, 2
which is a map with one key ("ten"), and two values for that key (10 and 11), as expected.
Live demo
PS: Storing pointers in a container like this is a bit uncommon in C++. If you really want to do this though, consider to use Smart Pointers.

Python's enumerate in c++

In Python , instead of
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
print i, '--->', colors[i]
One can write
for i, color in enumerate(colors):
print i, '--->', color
Is there a similar thing in c++?
You can actually implement something similar in c++17.
Here is a sketch(c++-ish pseudocode), I use values everywhere and they should be replaced by appropriate references/forwarding, also you should fix how you get types (use iterator_traits), may be support unknown size, may be implement proper iterator interface etc
template <typename T>
struct EnumeratedIterator {
size_t index;
T iterator;
void operator++() {
++iterator;
}
std::pair<size_t, T>() {
return {index, *iterator};
}
bool operator !=(EnumeratedIterator o) {
return iterator != o.iterator;
}
}
template <typename T>
struct Enumerated {
T collection;
EnumeratedIterator<typename T::iterator> begin() {
return {0, collection.begin()};
}
EnumeratedIterator<typename T::iterator> end() {
return {collection.size(), collection.end()};
}
}
auto enumerate(T col) {
return Enumerated<T>(col);
}
and then use it like
for (auto [index, color] : enumerate(vector<int>{5, 7, 10})) {
assert(index < color);
}
Boost provides an adaptor which allows to do something similiar:
http://www.boost.org/doc/libs/1_63_0/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
The following code is taken from the link above
#include <boost/range/adaptor/indexed.hpp>
#include <boost/assign.hpp>
#include <iterator>
#include <iostream>
#include <vector>
int main(int argc, const char* argv[])
{
using namespace boost::assign;
using namespace boost::adaptors;
std::vector<int> input;
input += 10,20,30,40,50,60,70,80,90;
for (const auto& element : input | indexed(0))
{
std::cout << "Element = " << element.value()
<< " Index = " << element.index()
<< std::endl;
}
return 0;
}
Maybe you can emulate it like this:
int i = 0;
for (auto color : { "red", "green", "blue", "yellow" })
std::cout << i++ << "--->" << color << std::endl;