Code for finding string between "" in a data structure - c++

I need help to solve the following:
Lets say I have the number 70368 in int var and that I want to find the corresponding string "EVT_ACP_CAPT_MIC_FLT" in the structure below and load it ( including the "") to a
char* event variable
The code solution must work for any number lenght between 1 to 5.
struct NameOffset TestEvents[] = {
{ "EVT_ACP_CAPT_LAST1", 70387 },
{ "EVT_ACP_CAPT_LAST1", 70387 },
{ "EVT_ACP_CAPT_LAST2", 70512 },
{ "EVT_ACP_CAPT_LAST2", 70512 },
{ "EVT_ACP_CAPT_MASK_BOOM_SWITCH", 70385 },
{ "EVT_ACP_CAPT_MIC_FLT", 70368 },
{ "EVT_ACP_CAPT_MIC_HF1", 70510 },
{ "EVT_ACP_CAPT_MIC_HF2", 70511 },
};
The table is in real very long, this is just a few lines to show the structure.

Assuming that the fields of struct NameOffset are Name and Offset, you can find a match using a loop, like this:
for (int i = 0 ; i != sizeof(TestEvents)/sizeof(struct NameOffset) ; i++) {
if (PmdgEvents[i].Offset == intVar) {
printf("%s\n", PmdgEvents[i].Name);
break;
}
}

The brute-force approach is to use a loop and compare the second struct member to identigfy the right struct.
If the code will be executed regularly, you should use a unordered_map: load the data to a unordered_map<int, string> (or char * instead of string if you like) and then use
event_map[code];
to access the string.
#include <unordered_map>
#include <iostream>
using namespace std;
struct NameOffset {
const char *event;
int code;
};
struct NameOffset TestEvents[] = {
{ "EVT_ACP_CAPT_LAST1", 70387 },
{ "EVT_ACP_CAPT_LAST2", 70512 },
{ "EVT_ACP_CAPT_MASK_BOOM_SWITCH", 70385 },
{ "EVT_ACP_CAPT_MIC_FLT", 70368 },
{ "EVT_ACP_CAPT_MIC_HF1", 70510 },
{ "EVT_ACP_CAPT_MIC_HF2", 70511 },
};
#define N_ELEMENTS (sizeof(TestEvents) / sizeof(NameOffset))
int main() {
unordered_map<int, const char *> event_map;
for (NameOffset *it = TestEvents, *it_end = TestEvents + N_ELEMENTS;
it != it_end; ++it) {
event_map[it->code] = it->event;
}
cout << event_map[70387] << endl;
cout << event_map[70512] << endl;
cout << event_map[70385] << endl;
cout << event_map[70368] << endl;
cout << event_map[70510] << endl;
cout << event_map[70511] << endl;
return 0;
}

Create a Map of <int,string> and then index the map with the corresponding value you want to search
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main (){
std::pair<int,string> TestEvents[] = {
make_pair( 70387,"EVT_ACP_CAPT_LAST1" ),
make_pair( 70???,"EVT_ACP_CAPT_LAST1" ),
make_pair( 70512,"EVT_ACP_CAPT_LAST2" ),
make_pair( 70512,"EVT_ACP_CAPT_LAST2" ),
make_pair( 70385, "EVT_ACP_CAPT_MASK_BOOM_SWITCH" ),
make_pair( 70368,"EVT_ACP_CAPT_MIC_FLT" ),
make_pair( 70510,"EVT_ACP_CAPT_MIC_HF1" ),
make_pair( 70511,"EVT_ACP_CAPT_MIC_HF2" )
};
map<int,string> mapTestEvents(TestEvents,TestEvents + sizeof TestEvents / sizeof TestEvents[0]);
int var = 70368;
const char* event = mapTestEvents[var].c_str();
return 0;
}
Please note, I assume the integer value is unique else the whole problem statement would be void.
And yet another way to do it using std::sort and std::lower_bound
#include<iostream>
#include<map>
#include<string>
#include<algorithm>
using namespace std;
struct NameOffset {
string name;
int offset;
};
NameOffset TestEvents[] = {
{ "EVT_ACP_CAPT_LAST1", 70387 },
{ "EVT_ACP_CAPT_LAST1", 70387 },
{ "EVT_ACP_CAPT_LAST2", 70512 },
{ "EVT_ACP_CAPT_LAST2", 70512 },
{ "EVT_ACP_CAPT_MASK_BOOM_SWITCH", 70385 },
{ "EVT_ACP_CAPT_MIC_FLT", 70368 },
{ "EVT_ACP_CAPT_MIC_HF1", 70510 },
{ "EVT_ACP_CAPT_MIC_HF2", 70511 },
};
bool CompareByEvent(NameOffset const& lhs, NameOffset const& rhs) {
return lhs.offset < rhs.offset;
}
int main (){
sort(TestEvents,TestEvents + sizeof TestEvents / sizeof TestEvents[0], &CompareByEvent);
NameOffset var = {"",70510};
const char* event =lower_bound(TestEvents,TestEvents + sizeof TestEvents / sizeof TestEvents[0], var,&CompareByEvent)->name.c_str();
return 0;
}

Related

How create a JSON-file from my data? (with ะก++, boost json)

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"
}
]
}
}
}

how to iterate over col in 2D vector c++?

I have the following vector of vector containning tree string elements, I want to know how to iterate over col element instead of normal loop over rows
vector<vector<string>> vec2Dstr =
{
{ "A2", "A4", "A6" },
{ "B2", "B4", "B6" },
{ "C2", "C4", "C6" },
{ "D2", "D4", "D6" },
{ "E2", "E4", "E6" }
};
the output expected is :
A2 B2 C2 D2 E2
A4 B4 C4 D4 E4
A6 B6 C6 D6 E6
code
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<vector<string>> vec2Dstr =
{
{ "A2", "A4", "A6" },
{ "B2", "B4", "B6" },
{ "C2", "C4", "C6" },
{ "D2", "D4", "D6" },
{ "E2", "E4", "E6" }
};
for(auto & j : vec2Dstr ) {
for(int i = 0 ; i < 3; i++ )
cout << " => " <<j.at(i) << endl;
}
return 0;
}
this following code might do the aim expected!
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<vector<string>> vec2Dstr =
{
{ "A2", "A4", "A6" },
{ "B2", "B4", "B6" },
{ "C2", "C4", "C6" },
{ "D2", "D4", "D6" },
{ "E2", "E4", "E6" }
};
size_t total_col = vec2Dstr[0].size();
for (int col=0; col<total_col; ++col)
{
for(auto& row : vec2Dstr)
{
cout << row[col] << " ";
}
cout << endl;
}
return 0;
}
Your for loops are wrong. How do you expect it to show 5 elements when you hardcode a limit of 3. Rewrite the for loop using this logic:
Iterate vec2Dstr from 0 to length.
Display vec2Dstr[i][j] where j increases after each loop we described above.
If you still are stuck after this let me know. Show me some code first.

how to access vector of map of ( int and vector of strings )

how do i access map of int and vectors of string in the passed_vector function.
I just want to print them in that function.
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;
typedef vector< map< int, vector<string> > > vmis;
typedef map< int, vector<string> > mis;
typedef vector<string> vstr;
void passing_vector(const vmis &meetings);
//return size of vector
template< typename A > size_t n_elements( const A& a )
{
return sizeof a / sizeof a[ 0 ];
}
int main()
{
vmis meeting_info;
mis meeting_members;
vstr sw_vec;
vstr sys_vec;
string sw_team[] = {"Ricky", "John", "David"};
string sys_team[] = {"Simmon", "Brad", "Schmidt", "Fizio"};
sw_vec.insert(sw_vec.begin(), sw_team, sw_team + n_elements(sw_team) );
sys_vec.insert(sys_vec.begin(), sys_team, sys_team + n_elements(sys_team) );
meeting_members.insert(make_pair(520, sw_vec));
meeting_members.insert(make_pair(440, sys_vec));
meeting_info.push_back(meeting_members);
passing_vector(meeting_info);
return 0;
}
void passing_vector(const vmis &meetings)
{
vmis::iterator itvmis = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
}
I know how to print them in main function.
vmis::iterator itvims = meeting_info.begin();
for( int i = 0; i < meeting_info.size(); i++ )
{
mis::iterator itm = meeting_members.begin();
for(itm; itm != meeting_members.end(); itm++ )
{
cout << itm->first << " : ";
vstr::iterator it = itm->second.begin();
for(it; it != itm->second.end(); it++)
cout << *it << " ";
cout << endl;
}
}
desired output
440 : Simmon Brad Schmidt Fizio
520 : Ricky John David
if there is a better way of doing this suggestions are always welcome.
The easiest aproach is to use auto, also since your meetings is const, you need to use const_iterator:
void passing_vector(const vmis &meetings)
{
vmis::const_iterator itvims = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
for (;itvims != meetings.end(); ++itvims)
{
const auto& map_item = *itvims;
for (const auto& map_it : map_item)
{
int map_key = map_it.first;
const auto& str_vec = map_it.second;
for (const auto& str : str_vec)
{
std::cout << map_key << " - " << str << "\n";
}
}
}
}
[edit]
c++98 version:
void passing_vector(const vmis &meetings)
{
vmis::const_iterator itvims = meetings.begin();
//how do i access map of int and vectors of string.
//I just want to print them.
for (;itvims != meetings.end(); ++itvims)
{
const mis& map_item = *itvims;
for (mis::const_iterator map_it = map_item.begin(); map_it != map_item.end(); ++map_it)
{
int map_key = map_it->first;
const vstr& str_vec = map_it->second;
for (vstr::const_iterator sitr = str_vec.begin(); sitr != str_vec.end(); ++sitr)
{
std::cout << map_key << " - " << *sitr << "\n";
}
}
}
}

Convert multimap<Key,Value> to vector<vector<Value>>

I need to convert an std::unordered_multimap<Key,T> to an std::vector<std::vector<T>>. I need to do this because my program will need to sort all the data, and maps can't be sorted. An example:
// Map:
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
// Map converted to vector<vector<Value>>:
{ 1, 3, 2 },
{ 5, 2 }
Right now I have this code which works. But I'm wondering if it's the best way to do it.
#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
int main()
{
typedef std::string Key_t;
typedef int Value_t;
typedef std::unordered_multimap<Key_t, Value_t> Map_t;
const Map_t map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector< std::vector< Value_t > > output;
for ( Map_t::const_iterator it = map.cbegin(); it != map.cend(); )
{
std::vector< Value_t > temp;
const Map_t::const_iterator end = map.upper_bound( it->first );
for ( ; it != end; ++it )
temp.push_back( it->second );
output.push_back( temp );
}
// Print the result
for ( const std::vector< Value_t >& values : output )
{
for ( const Value_t& value : values )
std::cout << value << " ";
std::cout << std::endl;
}
}
Output:
1 3 2
5 2
So, now I'm wondering if there's a faster/better way.
here's my attempt.
proof is here: http://goo.gl/JVpHw9
#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
typedef std::string Key_t;
typedef int Value_t;
typedef std::unordered_multimap<Key_t, Value_t> Map_t;
const Map_t map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector< std::vector< Value_t > > output;
for (auto it = map.begin(); it != map.end(); )
{
auto er = map.equal_range(it->first);
auto tmp = std::vector< Value_t >{};
for( ; it != er.second ; ++it) {
tmp.push_back(it->second);
};
output.push_back(std::move(tmp));
}
// Print the result
for ( const std::vector< Value_t >& values : output )
{
for ( const Value_t& value : values )
std::cout << value << " ";
std::cout << std::endl;
}
}
The usual multimap iteration should work here:
std::vector<std::vector<T>> out;
for (auto it1 = m.begin(), it2 = it1, end = m.end(); it1 != end; it1 = it2)
{
out.emplace_back();
for ( ; it1->first == it2->first; ++it2)
{
out.back().push_back(it2->second);
}
}
Following works for me:
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>
int main () {
std::unordered_multimap<std::string, int> map;
map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector<int> values;
std::transform(map.begin(), map.end(),
std::back_inserter(values),
[](std::pair<std::string, int> element) {
return element.second;
});
for (auto const& value : values) {
std::cout << value << std::endl;
}
return 0;
}

Binary Search and Sorting an Array by alphabetical order C++

I have a dynamic array which contains a contact number and name. I was wondering how to do a binary search for the name. Let's say I have 20 contacts and I want to find the number of the contact with name "John".
Here is the data structure:
struct Contact
{
int ContactNumber,Fax;
string Name, Email;
PhoneNumber Phone;
Address anAddress;
};
I have:
Contact * ptrFirst = & arrofCont[0];
Contact * ptrLast = & arrofCont[MAX - 1];
that contains the contact name and number and address etc. I guess those can be used as a first and last but don't know where to go from there.
You don't need to sort or binary search your array to do what you want.
Just use std::find_if.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
struct Company
{
std::string name ;
std::string number ;
};
struct HasName
{
HasName (const std::string &name) : name (name) {}
bool operator () (const Company &company) {
return company.name == name ;
}
std::string name ;
};
int main (void)
{
std::vector <Company> companies ;
// Fill up the vector...
std::vector <Company>::const_iterator citer ;
citer = std::find_if (companies.cbegin (), companies.cend (), HasName ("John")) ;
if (citer != companies.cend ()) {
std::cout << citer->number << "\n" ;
}
return 0 ;
}
Here is an example that uses a lambda expression to compare a pair of elements of the array
It corresponds to your original post before you updated it.
#include <iostream>
#include <algorithm>
#include <string>
struct Contact
{
std::string name;
int number;
};
int main()
{
const size_t N = 3; // or N = 20 or you can use name MAX instead of N
Contact *p = new Contact[N] { { "B", 2 }, { "A", 1 }, { "C", 3 } };
auto less_by_name = []( const Contact &c1, const Contact &c2 )
{
return ( c1.name < c2.name );
};
std::sort( p, p + N, less_by_name);
auto it = std::lower_bound( p, p + N, Contact( { "B", 0 } ), less_by_name );
if ( it != p + N ) std::cout << "The number of \"B\" is " << it->number << std::endl;
delete []p;
}
Or you can make the functor as a member of your class. For example
#include <iostream>
#include <algorithm>
#include <string>
struct Contact
{
std::string name;
int number;
static bool less_by_name( const Contact &c1, const Contact &c2 )
{
return ( c1.name < c2.name );
}
};
int main()
{
const size_t N = 3; // or N = 20 or you can use name MAX instead of N
Contact *p = new Contact[N] { { "B", 2 }, { "A", 1 }, { "C", 3 } };
std::sort( p, p + N, Contact::less_by_name);
auto it = std::lower_bound( p, p + N, Contact( { "B", 0 } ), Contact::less_by_name );
if ( it != p + N ) std::cout << "The number of \"B\" is " << it->number << std::endl;
delete []p;
}
As for your definitions
Contact * ptrFirst = & arrofCont[0];
Contact * ptrLast = & arrofCont[MAX - 1];
then if you will change them the following way
Contact * ptrFirst = arrofCont;
Contact * ptrLast = arrofCont + MAX;
then they will correspond to
Contact * ptrFirst = p;
Contact * ptrLast = p + N;
relative to my examples of code.