std::cout stopping the program - c++

I was trying to fix a bug, and I am extremely confused, it seems that whenever I use std::cout the program will freeze. I have absolutely no idea why this is happening, and if any of you I know why I would love to know.
here is my source code for reference (the std::cout is at the bottom in the main function):
#include <iostream>
#include <vector>
#include <unordered_map>
#include <exception>
#include <string>
#include <fstream>
/*
template<
typename T
>
std::ostream& operator<< (std::ostream& stream, std::vector<T> vec)
{
for (int i = 0; i < vec.size() - 1; ++i)
{
stream << vec[i] << " ";
}
stream << vec.back();
return stream;
}
*/
class gate
{
public:
std::unordered_map<std::string, int> m_inputs;
std::unordered_map<std::string, int> m_outputs;
virtual std::vector<bool> calculate(const std::vector<bool>& inputs) = 0;
gate(const std::unordered_map<std::string, int>& inputs, const std::unordered_map<std::string, int>& outputs) :
m_inputs(inputs),
m_outputs(outputs)
{}
};
class elementary_gate : public gate
{
private:
std::unordered_map<std::vector<bool>, std::vector<bool>> m_truth_table;
public:
elementary_gate(const std::unordered_map<std::vector<bool>, std::vector<bool>>& truth_table,
const std::unordered_map<std::string, int>& inputs,
const std::unordered_map<std::string, int>& outputs
) :
gate(inputs, outputs),
m_truth_table(truth_table)
{}
std::vector<bool> calculate(const std::vector<bool>& inputs) override
{
return m_truth_table[inputs];
}
};
class gate_reference
{
private:
gate* m_gate;
std::vector<int> m_input_connection_ids;
std::vector<int> m_output_connection_ids;
public:
gate_reference(gate* gate_ref, const std::vector<int>& input_connection_ids, const std::vector<int>& output_connection_ids) :
m_gate(gate_ref),
m_input_connection_ids(input_connection_ids),
m_output_connection_ids(output_connection_ids)
{}
std::vector<bool> calculate(const std::vector<bool>& inputs)
{
return m_gate->calculate(inputs);
}
std::vector<int> get_input_connection_ids()
{
return m_input_connection_ids;
}
void set_output_connection_ids(const std::vector<bool>& output_vector, std::vector<bool>& connection_values)
{
for (int i = 0; i < output_vector.size(); ++i)
{
connection_values[m_output_connection_ids[i]] = output_vector[i];
}
}
};
class compound_gate : public gate
{
private:
std::vector<gate_reference> m_gates;
std::vector<int> m_output_connection_ids;
int connection_count;
int input_count;
public:
std::vector<bool> calculate(const std::vector<bool>& inputs) override
{
if (inputs.size() != input_count)
{
throw std::length_error("incorrect input size for logic gate");
}
std::vector<bool> connection_values(connection_count);
for (int i = 0; i < input_count; ++i)
{
connection_values[i] = inputs[i];
}
for (gate_reference gate_ref : m_gates)
{
std::vector<int> input_ids = gate_ref.get_input_connection_ids();
std::vector<bool> input_vector = construct_io_vector(input_ids, connection_values);
std::vector<bool> output_vector = gate_ref.calculate(input_vector);
gate_ref.set_output_connection_ids(output_vector, connection_values);
}
return construct_io_vector(m_output_connection_ids, connection_values);
}
private:
std::vector<bool> construct_io_vector(const std::vector<int>& connection_ids, const std::vector<bool>& connection_values)
{
std::vector<bool> input_vector;
for (int connection_id : connection_ids)
{
input_vector.push_back(connection_values[connection_id]);
}
return input_vector;
}
};
std::vector<bool> get_vector_from_int(int num, int pad_length)
{
std::vector<bool> bool_vec;
while (num)
{
if (num % 2)
{
bool_vec.push_back(true);
}
else
{
bool_vec.push_back(false);
}
num >>= 1;
}
while (bool_vec.size() < pad_length)
{
bool_vec.push_back(false);
}
std::reverse(bool_vec.begin(), bool_vec.end());
return bool_vec;
}
class gates
{
public:
static std::unordered_map<std::string, elementary_gate*> gate_list;
};
std::unordered_map<std::string, elementary_gate*> gates::gate_list;
gate* load_elementary_gate(const std::string& filename)
{
std::ifstream file(filename);
std::string gate_name = filename.substr(0, filename.find('.'));
int input_count;
file >> input_count;
std::unordered_map<std::string, int> inputs;
for (int i = 0; i < input_count; ++i)
{
std::string input_name;
file >> input_name;
inputs.insert(std::make_pair(input_name, i));
}
int output_count;
file >> output_count;
std::unordered_map<std::string, int> outputs;
for (int i = 0; i < output_count; ++i)
{
std::string output_name;
file >> output_name;
outputs.insert(std::make_pair(output_name, i));
}
int table_rows = 1 << input_count;
std::unordered_map<std::vector<bool>, std::vector<bool>> truth_table;
for (int i = 0; i < table_rows; ++i)
{
std::vector<bool> input_vector = get_vector_from_int(i, input_count);
std::vector<bool> output_vector(output_count);
for (int i = 0; i < output_count; ++i)
{
int val;
file >> val;
output_vector[i] = val;
}
truth_table.insert(std::make_pair(input_vector, output_vector));
}
elementary_gate* gate = new elementary_gate(truth_table, inputs, outputs);
gates::gate_list.insert(std::make_pair(gate_name, gate));
return gate;
}
gate* extract_gate_type(std::string& raw_gate)
{
std::string gate_name = raw_gate.substr(0, raw_gate.find('('));
raw_gate = raw_gate.substr(raw_gate.find('(') + 1, raw_gate.size() - raw_gate.find('(')- 2);
return gates::gate_list[gate_name];
}
std::vector<std::string> split_string(std::string str, char delim)
{
std::vector<std::string> split;
bool new_str = true;
for (char c : str)
{
if (new_str)
{
split.emplace_back("");
}
if (c == delim)
{
new_str = true;
}
else
{
if (c != ' ')
{
new_str = false;
split.back() += c;
}
}
}
return split;
}
gate* load_circuit(const std::string& filename)
{
std::ifstream file(filename);
std::string gate_name = filename.substr(0, filename.find('.'));
int input_count;
file >> input_count;
std::unordered_map<std::string, int> inputs;
for (int i = 0; i < input_count; ++i)
{
std::string input_name;
file >> input_name;
inputs.insert(std::make_pair(input_name, i));
}
int output_count;
file >> output_count;
std::unordered_map<std::string, int> outputs;
for (int i = 0; i < output_count; ++i)
{
std::string output_name;
file >> output_name;
outputs.insert(std::make_pair(output_name, i));
}
std::vector<gate*> gates;
std::vector<std::string> sub_gates_raw;
while (!file.eof())
{
std::string gate_str;
char c = ' ';
while (c != ')')
{
file >> c;
gate_str += c;
}
std::cout << gate_str.size() << std::endl;
if (gate_str.size() < 1)
{
continue;
}
gates.push_back(extract_gate_type(gate_str));
sub_gates_raw.push_back(gate_str);
}
std::vector<std::vector<std::string>> io_split;
for (std::string str : sub_gates_raw)
{
io_split.push_back(split_string(str, ','));
}
std::vector<std::vector<std::pair<std::string, std::string>>> gate_io_split;
for (std::vector<std::string> gate_strs : io_split)
{
std::vector<std::pair<std::string, std::string>> gate_strs_lr_split;
for (std::string io_str : gate_strs)
{
std::vector<std::string> gate_str_lr_split = split_string(io_str, '=');
gate_strs_lr_split.push_back(std::make_pair(gate_str_lr_split[0], gate_str_lr_split[1]));
}
gate_io_split.push_back(gate_strs_lr_split);
}
std::unordered_map<std::string, int> connection_list;
for (std::vector<std::pair<std::string, std::string>> gate_strs : gate_io_split)
{
for (std::pair<std::string, std::string> connection : gate_strs)
{
connection_list.insert(std::make_pair(connection.first, connection_list.size() - 1));
}
}
for (std::pair<std::string, int> input : inputs)
{
inputs.insert_or_assign(input.first, connection_list[input.first]);
}
for (std::pair<std::string, int> output : outputs)
{
outputs.insert_or_assign(output.first, connection_list[output.first]);
}
std::vector<std::vector<std::pair<int, int>>> gates_connection_indexes;
std::vector<std::vector<bool>> is_input;
for (int i = 0; i < gate_io_split.size(); ++i)
{
std::vector<std::pair<std::string, std::string>> gate_connection_indexes_str = gate_io_split[i];
std::vector<std::pair<int, int>> gate_connection_indexes;
std::vector<bool> gate_connections;
for (std::pair<std::string, std::string> gate_connection_index_str : gate_connection_indexes_str)
{
gate_connections.push_back(gates[i]->m_inputs.count(gate_connection_index_str.first));
std::pair<int, int> connnection_indexes = std::make_pair(connection_list[gate_connection_index_str.first], connection_list[gate_connection_index_str.second]);
gate_connection_indexes.push_back(connnection_indexes);
}
is_input.push_back(gate_connections);
gates_connection_indexes.push_back(gate_connection_indexes);
}
std::vector<gate_reference> gate_references;
for (int i = 0; i < gates_connection_indexes.size(); ++i)
{
}
return nullptr;
}
int main(void)
{
std::cout << "hello";
//load_elementary_gate("nand.gate");
//load_circuit("not.circuit");
//load_circuit("or.circuit");
return 0;
}

Related

Custom structure as key in unordered_map

I want to use structure Item as key in unordered_map
I implemented structures for hash and equal operations.
But I have an error
hashtable_policy.h:1384:16: error: no match for call to '(const ItemHash) (const Item&)'
solution.cpp:28:12: note: candidate: 'size_t ItemHash::operator()(Item)'
32 | size_t operator()(Item item) {
solution.cpp:28:12: note: passing 'const ItemHash*' as 'this' argument discards qualifiers
How can I fix the error?
My code
vector<int> get_key(const string& s) {
vector<int> res(26, 0);
for (int i = 0; i < s.size(); ++i) {
int pos = s[i] - 'a';
res[pos]++;
}
return res;
}
struct Item {
vector<int> v;
Item(const vector<int>& vec) : v(vec) {}
bool operator==(Item other) {
if (v.size() != other.v.size()) {
return false;
}
for (int i = 0; i < v.size(); ++i) {
if (v[i] != other.v[i]) {
return false;
}
}
return true;
}
};
struct ItemHash {
size_t operator()(Item item) {
auto vec = item.v;
size_t seed = vec.size();
for(auto& i : vec) {
seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
struct ItemEqual {
bool operator()(Item item1, Item item2) {
return item1 == item2;
}
};
vector<vector<int> > Solution::anagrams(const vector<string> &A) {
vector<vector<int>> res;
unordered_map<Item, vector<int>, ItemHash, ItemEqual> hash; // hash_key, vector of indexes
for (int i = 0; i < A.size(); ++i) {
Item item = Item(get_key(A[i]));
hash[item].push_back(i);
}
for (const auto& i : hash) {
res.push_back(i.second);
}
return res;
}
You need to const-qualify ItemHash::operator()(Item), i.e.,
struct ItemHash {
size_t operator()(Item item) const
// ^^^^ here
{
// as before...
}
Note that as #JeJo pointed out in the comments, you need the same fix for ItemEqual.

Creating std::set copies only one element, how to fix this?

v_map has the correct amount of information stored, however when i try to use std::set it only copies one element ,I assume the first one. This is my first time using std::set , maybe I miss something here...Thanks for your help !
typedef std::map<std::string,std::pair<int,int>> points_map;
void list_average(points_map &v_map)
{
Comparator compFunctor = [](std::pair<std::string,std::pair<int,int>> elem1,std::pair<std::string,std::pair<int,int>> elem2)
{
std::pair<int,int> it = elem1.second;
std::pair<int,int> jt = elem2.second;
return it.first < jt.first;
};
std::set<std::pair<std::string,std::pair<int,int>>,Comparator> v_set(v_map.begin(),v_map.end(),compFunctor);
for (std::pair<std::string,std::pair<int,int>> it : v_set)
{
std::pair<int,int> jt = it.second;
std::cout << it.first << " " << (jt.second - jt.first) / jt.first<< std::endl;
}
}
Note the following is the full program, I apologize in advance for the ugly code , and length of the code ,also I rewrote the name in the upper part of my code, in the full code , this particular function is called list_atlag
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <codecvt>
#include <iterator>
#include <numeric>
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/tokenizer.hpp>
class Adatok
{
public:
Adatok(std::string name, std::string path, std::string date, int points) : _name(name), _path(path), _date(date), _points(points) {}
Adatok(const Adatok &other) = default;
Adatok &operator=(const Adatok &other) = default;
std::string get_name() { return _name; }
std::string get_path() { return _path; }
std::string get_date() { return _date; }
int get_points() { return _points; }
private:
std::string _name;
std::string _path;
std::string _date;
int _points;
};
class Ranglista
{
public:
Ranglista(std::string name, int points) : _name(name), _points(points) {}
Ranglista(const Ranglista &other) = default;
Ranglista &operator=(const Ranglista &other) = default;
std::string get_name() { return _name; }
int get_points() { return _points; }
bool operator<(const Ranglista &other)
{
return _points > other._points;
}
private:
std::string _name;
int _points;
};
class Vedes
{
public:
Vedes(std::string name, int point) : _name(name), _point(point) { _count++; }
Vedes(const Vedes &other) = default;
Vedes &operator=(const Vedes &other) = default;
std::string get_name() { return _name; }
int get_point() { return _point; }
int get_count() { return _count; }
void set_stuff(int &points)
{
_point += points;
_count++;
}
bool operator<(const Vedes &other)
{
return _count > other._count;
}
private:
std::string _name;
int _point;
int _count = 0;
};
typedef std::map<std::string, int> path_value; //minden path + az erteke
typedef std::vector<Adatok> name_path_date; //bejegyzesek
typedef std::vector<Ranglista> ranglista; //ranglista
typedef std::map<std::string,std::pair<int,int>> vedes_vec; //vedesek
typedef std::function<bool(std::pair<std::string,std::pair<int,int>>,std::pair<std::string,std::pair<int,int>>)> Comparator;
void create_pv(path_value &, boost::filesystem::path); //feltolti a path+ertek map-ot
void create_npd(name_path_date &, path_value &, std::string input); //feltolti a bejegyzesek vektorat + mindenki pontszama map
void create_np(name_path_date &, path_value &); // name + path map
void list_np(path_value &name_point); // nam + path kiiratas
void list_bejegyzesek(name_path_date &bejegyzesek); // bejegyzesek vektora kiiratas
bool check_bejegyzesek(name_path_date &bejegyzesek, std::string name, std::string path); //van-e mar ilyen bejegyzes
void create_rl(ranglista &rl_vec, path_value &name_point); //ranglista feltoltes
void list_rl(ranglista &rl_vec); //ranglista kiiratas
void vedes_atlag(name_path_date &bejegyzesek, vedes_vec &v_vec); //vedes atlag map
void list_atlag(vedes_vec &v_vec); //vedes atlag kiiratas
bool check_vedes(vedes_vec &v_vec, std::string name);
void vedes_elem(vedes_vec &v_vec, std::string name, int &&points); //
//void accumulate_pv(path_value&);
int main(int argc, char **argv)
{
std::vector<std::string> roots = {"City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/", "City/Debrecen/Oktatás/Informatika/Programozás/DEIK/"};
std::string input_file_name = "db-2018-05-06.csv";
/* OPTIONS */
boost::program_options::options_description desc("ALLOWED OPTIONS");
desc.add_options()("help", "help msg")("root,r", boost::program_options::value<std::vector<std::string>>())("csv", boost::program_options::value<std::string>(), "comma separated values")("rank", "rang lista")("vedes", "labor vedesek");
boost::program_options::positional_options_description pdesc;
pdesc.add("root", -1);
boost::program_options::variables_map vm;
boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(desc).positional(pdesc).run(), vm);
boost::program_options::notify(vm);
int sum = 0;
path_value pv_map;
if (vm.count("help") || argc == 1)
{
std::cout << desc << std::endl;
return 1;
}
if (vm.count("root"))
{
roots = vm["root"].as<std::vector<std::string>>();
for (auto &i : roots)
{
boost::filesystem::path path(i);
create_pv(pv_map, path);
}
for (path_value::iterator it{pv_map.begin()}; it != pv_map.end(); it++)
sum += it->second;
//std::cout << sum << std::endl;create_npd
std::cout << std::accumulate(pv_map.begin(), pv_map.end(), 0, [](int value, const std::map<std::string, int>::value_type &p) { return value + p.second; });
std::cout << std::endl;
}
if (vm.count("csv"))
{
//input_file_name = vm["csv"].as<std::string>();
std::ifstream input_file{vm["csv"].as<std::string>()};
name_path_date bejegyzesek;
std::string temp;
path_value name_point;
while (getline(input_file, temp))
create_npd(bejegyzesek, pv_map, temp);
create_np(bejegyzesek, name_point);
//list_bejegyzesek(bejegyzesek);
//list_np(name_point);
if (vm.count("rank"))
{
ranglista rl_vec;
create_rl(rl_vec, name_point);
list_rl(rl_vec);
}
if (vm.count("vedes"))
{
vedes_vec v_vec;
vedes_atlag(bejegyzesek, v_vec);
list_atlag(v_vec);
}
return 0;
}
return 0;
}
void create_pv(path_value &pv_map, boost::filesystem::path path)
{
boost::filesystem::directory_iterator it{path}, eod;
BOOST_FOREACH (boost::filesystem::path const &p, std::make_pair(it, eod))
{
if (boost::filesystem::is_regular_file(p))
{
boost::filesystem::ifstream regular_file{p};
std::string temp;
int sum = 0; //aktualis .props erteke
while (getline(regular_file, temp))
{
temp.erase(0, temp.find_last_of('/'));
temp.erase(0, temp.find_first_of(' '));
sum += std::atoi((temp.substr(temp.find_first_of("0123456789"), temp.find_last_of("0123456789"))).c_str());
}
std::string result = p.string();
std::string result_path = result.substr(0, result.find_last_of('/'));
//std::cout << result_path << std::endl;
//pv_map.insert(std::make_pair(result, sum));
pv_map[result_path] = sum;
}
else
create_pv(pv_map, p);
}
}
//void accumulate_pv(path_value& pv_map)
//{
// std::cout<<std::accumulate(pv_map.begin(),pv_map.end(),0,[](int value,const path_value::int& p){return value+p.second;});
//}
void create_npd(name_path_date &bejegyzesek, path_value &pv_map, std::string input)
{
boost::tokenizer<boost::escaped_list_separator<char>> tokenizer{input};
boost::tokenizer<boost::escaped_list_separator<char>>::iterator it{tokenizer.begin()};
std::string name = *it;
std::string path = *(++it);
std::string date = *(++it);
path = path.substr(2);
if (!check_bejegyzesek(bejegyzesek, name, path))
bejegyzesek.push_back(Adatok(name, path, date, pv_map["/home/erik/Documents/Programs/"+path]));
}
bool check_bejegyzesek(name_path_date &bejegyzesek, std::string name, std::string path)
{
bool ok = false;
for (name_path_date::iterator it{bejegyzesek.begin()}; it != bejegyzesek.end(); it++)
{
if ((it->get_name() == name) && (it->get_path() == path))
ok = true;
}
return ok;
}
bool check_vedes(vedes_vec &v_vec, std::string name)
{
vedes_vec::iterator it = v_vec.find(name);
if (it != v_vec.end()) return true;
else return false;
}
void vedes_elem(vedes_vec &v_vec, std::string name, int &&points)
{
/*for (auto &it : v_vec)
if (it.get_name() == name)
it.set_stuff(points);
*/
vedes_vec::iterator i = v_vec.find(name);
std::pair<int,int> it = i->second;
//auto& jt = it->second;
it.first++;
it.second += points;
}
void create_np(name_path_date &bejegyzesek, path_value &name_point)
{
for (name_path_date::iterator it{bejegyzesek.begin()}; it != bejegyzesek.end(); it++)
if (name_point.count(it->get_name()) == 0)
name_point.insert(std::make_pair(it->get_name(), it->get_points()));
else
name_point[it->get_name()] += it->get_points();
}
void list_np(path_value &name_point)
{
for (path_value::iterator it{name_point.begin()}; it != name_point.end(); it++)
{
if (it->second)
std::cout << it->first << " " << it->second << std::endl;
}
}
void list_bejegyzesek(name_path_date &bejegyzesek)
{
for (name_path_date::iterator it{bejegyzesek.begin()}; it != bejegyzesek.end(); it++)
if (it->get_name() == "Varga Erik")
std::cout << it->get_name() << " " << it->get_path() << " " << it->get_points() << std::endl;
}
void create_rl(ranglista &rl_vec, path_value &name_point)
{
for (auto &it : name_point)
{
if (it.second > 0)
rl_vec.push_back(Ranglista(it.first, it.second));
}
std::sort(rl_vec.begin(), rl_vec.end());
}
void list_rl(ranglista &rl_vec)
{
for (auto &it : rl_vec)
std::cout << it.get_name() << " " << it.get_points() << std::endl;
}
void vedes_atlag(name_path_date &bejegyzesek, vedes_vec &v_vec)
{
std::string key = "City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/Labor/Védés/";
for (auto &it : bejegyzesek)
{
if ((it.get_path().find("City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/Labor/Védés/") != std::string::npos) && (it.get_points()) && (!check_vedes(v_vec, it.get_name())))
v_vec.insert(std::make_pair(it.get_name(),std::make_pair(1,it.get_points())));
else if ((check_vedes(v_vec, it.get_name())) && (it.get_path().find("City/Debrecen/Oktatás/Informatika/Programozás/DEIK/Prog1/Labor/Védés/") != std::string::npos) && (it.get_points()))
vedes_elem(v_vec, it.get_name(), it.get_points());
}
}
void list_atlag(vedes_vec &v_vec)
{
//std::sort(v_vec.begin(), v_vec.end());
Comparator compFunctor = [](std::pair<std::string,std::pair<int,int>> elem1,std::pair<std::string,std::pair<int,int>> elem2)
{
std::pair<int,int> it = elem1.second;
std::pair<int,int> jt = elem2.second;
return it.first < jt.first;
};
std::set<std::pair<std::string,std::pair<int,int>>,Comparator> v_set(v_vec.begin(),v_vec.end(),compFunctor);
//int sum = 0;
//int csum = 0;
for (std::pair<std::string,std::pair<int,int>> it : v_set)
{
std::pair<int,int> jt = it.second;
std::cout << it.first << " " << (jt.second - jt.first) / jt.first<< std::endl;
//sum += it.get_point();
//csum += it.get_count();
//sum = std::accumulate(v_vec.begin(), v_vec.end(), 0, [](int i, Vedes &o) { return i + o.get_point(); });
//csum = std::accumulate(v_vec.begin(), v_vec.end(), 0, [](int i, Vedes &o) { return i + o.get_count(); });
}
//std::cout << (sum - csum) / csum << std::endl;
}
so, as described here
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
std::set is an associative container that contains a sorted set of unique objects of type Key.
I cleaned up your code, and made a Minimal, Complete, and Verifiable example,
#include <iostream>
#include <map>
#include <set>
using point_pair = std::pair<int,int>;
using points_map = std::map<std::string, point_pair>;
using points_set_pair = std::pair<std::string, point_pair>;
auto compFunctor = [](const points_set_pair &elem1, const points_set_pair &elem2)
{
return elem1.second.first < elem2.second.first;
};
using points_set = std::set<points_set_pair, decltype(compFunctor)>;
void list_average(const points_map &v_map)
{
points_set v_set(v_map.begin(),v_map.end(),compFunctor);
for (auto &elem : v_set)
{
const point_pair &jt = elem.second;
std::cout << elem.first << " " << (jt.second - jt.first) / jt.first<< "\n";
}
}
Now consider the first version of main
int main()
{
points_map v_map = { {"foo", { 1, 2}}, {"bar", { 3, 4}}};
list_average(v_map);
}
output:
foo 1
bar 0
Now consider the second version of main:
int main()
{
points_map v_map = { {"foo", { 1, 2}}, {"bar", { 1, 4}}};
list_average(v_map);
}
output:
bar 3
See the problem? As .second.first of the elements are both 1, the latter replaces the first. It is not unique. That's the downside of std::set.
So, what then?
Don't use std::set, but use std::vector and std::sort. Example:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using point_pair = std::pair<int,int>;
using points_map = std::map<std::string, point_pair>;
using string_point_pair = std::pair<std::string, point_pair>;
auto compFunctor = [](string_point_pair const &elem1, string_point_pair const &elem2)
{
return
elem1.second.first != elem2.second.first?
elem1.second.first < elem2.second.first:
elem1.second.second < elem2.second.second;
};
void list_average(points_map const &v_map)
{
std::vector<string_point_pair> v_vec(v_map.begin(),v_map.end());
std::sort(v_vec.begin(), v_vec.end(), compFunctor);
for (auto &elem : v_vec)
{
const point_pair &jt = elem.second;
std::cout << elem.first << " " << (jt.second - jt.first) / jt.first<< "\n";
}
}
int main()
{
points_map v_map = { {"foo", { 1, 2}}, {"bar", { 1, 4}}, {"baz", { 2, 4}}};
list_average(v_map);
}
Output:
foo 1
bar 3
baz 1
live demo

Implementing Adapter into c++ program

I am trying to implement Adapter which would enable me to use class "TecajnaLista" with function Statistika::prosjek.
End result I am looking for is to call function Statistika::prosjek like this:
> map<string, tuple<double, int>> pr = Statistika::prosjek(adapter);
Insted of this:
> map<string, tuple<double, int>> pr = Statistika::prosjek(p);
Program without Adapter looks like this:
Za_adaptaciju.h
#pragma once
#include <fstream>
#include <vector>
#include <map>
using namespace std;
//=============================================================================
//=============================================================================
//=============================================================================
namespace PostojeciProgram {
class ITecaj {
public:
virtual void ucitaj(fstream*) = 0;
virtual const vector<tuple<string, double>>* podaci() const = 0;
};
class Tecaj : public ITecaj {
public:
void ucitaj(fstream*);
const vector<tuple<string, double>>* podaci() const;
private:
vector<tuple<string, double>> vrijednosti;
};
class Statistika {
public:
static map<string, tuple<double, int>> prosjek(ITecaj&);
};
void ispisi(map<string, tuple<double, int>>& pr);
void ispisi_tecaj();
}
Za_adaptaciju.cpp
#include <string>
#include <iostream>
#include "za_adaptaciju.h"
//=============================================================================
//=============================================================================
//=============================================================================
namespace PostojeciProgram {
void Tecaj::ucitaj(fstream* datoteka) {
string red;
while (true) {
*datoteka >> red;
if (datoteka->eof()) {
break;
} else {
int zarez = red.find(',');
string mjesec = red.substr(0, zarez);
double cijena = atof(red.substr(zarez + 1, red.size()).c_str());
vrijednosti.push_back({mjesec, cijena});
}
}
}
const vector<tuple<string, double>>* Tecaj::podaci() const {
return &vrijednosti;
}
map<string, tuple<double, int>> Statistika::prosjek(ITecaj& tecaj) {
map<string, tuple<double, int>> prosjek;
for (tuple<string, double> v : *(tecaj.podaci())) {
string kljuc = get<0>(v);
double nova_vrijednost = get<1>(v);
tuple<double, int>& p = prosjek[kljuc];
double vrijednost = get<0>(p);
int broj_pojavljivanja = get<1>(p);
if (broj_pojavljivanja == 0) {
prosjek[kljuc] = {nova_vrijednost, 1};
} else {
prosjek[kljuc] = {vrijednost + nova_vrijednost, broj_pojavljivanja + 1};
}
}
return prosjek;
}
void ispisi(map<string, tuple<double, int>>& pr) {
for (auto v : pr) {
string kljuc = get<0>(v);
tuple<double, int> v = pr[kljuc];
double n = get<0>(v) / get<1>(v);
cout << kljuc << ": " << n << endl;
}
}
void ispisi_tecaj() {
Tecaj p;
fstream f;
f.open("tecaj_eur.csv", fstream::in);
p.ucitaj(&f);
map<string, tuple<double, int>> pr = Statistika::prosjek(p);
ispisi(pr);
}
}
Main.cpp
#include <iostream>
#include "za_adaptaciju.h"
using namespace PostojeciProgram;
void test_adapter() {
cout << "--- TECAJ - klasa Tecaj\n";
ispisi_tecaj();
cout << endl;
}
int main() {
test_adapter();
}
My attempt:
Za_adaptaciju.h
#pragma once
#include <fstream>
#include <vector>
#include <map>
using namespace std;
//=============================================================================
//=============================================================================
//=============================================================================
namespace PostojeciProgram {
class ITecaj {
public:
virtual void ucitaj(fstream*) = 0;
virtual const vector<tuple<string, double>>* podaci() const = 0;
};
class Tecaj : public ITecaj {
public:
void ucitaj(fstream*);
const vector<tuple<string, double>>* podaci() const;
private:
vector<tuple<string, double>> vrijednosti;
};
class TecajnaLista {
public:
void ucitaj_valutu(string ime_datoteke);
const vector<tuple<string, double>>* podaci() const;
private:
vector<tuple<string, double>> vrijednosti;
};
/* ########################### moj adapter #################################################*/
class Adapter : public TecajnaLista {
public:
void ucitaj_valutu(string ime_datoteke) {
stream.open("tecaj_eur.csv", fstream::in);
tecaj.ucitaj(&stream);
}
const vector<tuple<string, double>>* podaci() const {
tecaj.podaci();
return &vrijednosti;
}
protected:
vector<tuple<string, double>> vrijednosti;
PostojeciProgram::ITecaj* itecaj;
PostojeciProgram::Tecaj tecaj;
fstream stream;
};
class Statistika {
public:
static map<string, tuple<double, int>> prosjek(Adapter& adapter);
};
void ispisi(map<string, tuple<double, int>>& pr);
void ispisi_tecaj();
}
za_adaptaciju.cpp
#include <string>
#include <iostream>
#include "za_adaptaciju.h"
//=============================================================================
//=============================================================================
//=============================================================================
namespace PostojeciProgram {
void Tecaj::ucitaj(fstream* datoteka) {
string red;
while (true) {
*datoteka >> red;
if (datoteka->eof()) {
break;
} else {
int zarez = red.find(',');
string mjesec = red.substr(0, zarez);
double cijena = atof(red.substr(zarez + 1, red.size()).c_str());
vrijednosti.push_back({mjesec, cijena});
}
}
}
const vector<tuple<string, double>>* Tecaj::podaci() const {
return &vrijednosti;
}
map<string, tuple<double, int>> Statistika::prosjek(Adapter& tecaj) {
map<string, tuple<double, int>> prosjek;
for (tuple<string, double> v : *(tecaj.podaci())) {
string kljuc = get<0>(v);
double nova_vrijednost = get<1>(v);
tuple<double, int>& p = prosjek[kljuc];
double vrijednost = get<0>(p);
int broj_pojavljivanja = get<1>(p);
if (broj_pojavljivanja == 0) {
prosjek[kljuc] = {nova_vrijednost, 1};
} else {
prosjek[kljuc] = {vrijednost + nova_vrijednost, broj_pojavljivanja + 1};
}
}
return prosjek;
}
void ispisi(map<string, tuple<double, int>>& pr) {
for (auto v : pr) {
string kljuc = get<0>(v);
tuple<double, int> v = pr[kljuc];
double n = get<0>(v) / get<1>(v);
cout << kljuc << ": " << n << endl;
}
}
void ispisi_tecaj() {
Tecaj p;
Adapter adapter;
adapter.ucitaj_valutu("tecaj_eur.csv");
map<string, tuple<double, int>> pr = Statistika::prosjek(adapter);
ispisi(pr);
}
}
Program is compiling but I am getting empty result instead of expected result which I am getting with program without adapter :
Result of program execution without adapter
Thank you in advance!

Slow performance using STL in NEH algorithm

I've got problem with NEH algorithm. I implemented it but it's veeeery slow and I can't figure out what the problem is. Could You verify what I did wrong, what causes bad performance? Here's my code:
#include <iostream>
#include <map>
#include <sstream>
#include <limits>
#include <vector>
#include <fstream>
#include <list>
#include <algorithm>
#include <numeric>
#include <queue>
#include <memory>
template <typename T>
class Matrix
{
public:
Matrix(unsigned int rowsNum, unsigned int columnsNum) :m_rows(rowsNum), m_columns(columnsNum){ resize(rowsNum, columnsNum); };
T& operator()(unsigned int r, unsigned int c) { return m_data[r*columns() + c]; }
const T& operator()(unsigned int r, unsigned int c) const { return m_data[r*columns() + c]; }
unsigned int rows() const { return m_rows; }
unsigned int columns() const { return m_columns; }
Matrix<T> operator+(const Matrix<T>& matrix) const;
private:
void resize(unsigned int rowsNum, unsigned int colsNum);
std::unique_ptr<T[]> m_data;
unsigned int m_rows;
unsigned int m_columns;
};
template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix& matrix) const
{
}
template <typename T>
void Matrix<T>::resize(unsigned int rowsNum, unsigned int colsNum)
{
m_rows = rowsNum;
m_columns = colsNum;
m_data.reset(new T[rowsNum*colsNum]);
}
class Task
{
public:
Task(unsigned int ordNum = 0) :m_ordNum(ordNum) { }
unsigned int readFromFile(std::istream& is);
unsigned int totalTasksTime() const;
unsigned int ordNum() const { return m_ordNum; }
unsigned int machinesNum() const { return m_params.size(); }
unsigned int machineTaskTime(unsigned int machineNum) const { return m_params[machineNum - 1]; }
protected:
std::vector<unsigned int> m_params;
unsigned int m_ordNum;
unsigned int m_totalTasksTime;
};
unsigned int Task::totalTasksTime() const
{
return m_totalTasksTime;
}
unsigned int Task::readFromFile(std::istream& is)
{
std::string line;
while (is.peek() == '\n') // omija puste linie
is.get();
std::getline(is, line);
m_params.clear();
std::istringstream istr(line);
unsigned int i = 1;
while (istr)
{
int taskNum, taskTime;
istr >> taskNum >> taskTime;
if (istr)
{
if (i == m_params.size() + 1)
m_params.push_back(taskTime);
else
throw "Zly numer indesku maszyny - musza być po kolei";
i++;
}
}
m_totalTasksTime = std::accumulate(m_params.begin(), m_params.end(), 0);
return m_params.size();
}
class Instance
{
public:
Instance() { }
Instance(const std::string& name) :m_name(name) { }
void readFromFile(std::istream& is);
const std::string& name() const { return m_name; }
void name(std::string& newName) { m_name = newName; }
void neh(std::list<unsigned int>& permutation, unsigned int &totalTime) const;
const Task* getTask(unsigned int taskNum) const { return &m_tasks[taskNum]; }
private:
unsigned int calculateTotalTime(const std::list<unsigned int>& permutationList, unsigned int bestTimeFound) const;
std::vector<Task> m_tasks;
std::string m_name;
};
typedef std::map<unsigned int, unsigned int> MapIterator;
typedef std::vector<Task>::const_iterator TaskVecIterator;
bool compareTasksPtrBySumTime(const Task* t1, const Task* t2)
{
unsigned int t1TotalTime = t1->totalTasksTime(), t2TotalTime = t2->totalTasksTime();
bool w1 = t1TotalTime < t2TotalTime, w2 = t1TotalTime == t2TotalTime && t1->ordNum() > t2->ordNum();
return w1 || w2;
}
void Instance::neh(std::list<unsigned int>& permutation, unsigned int &totalTime) const
{
// sortowanie zadań po całkowitym czasie wykonania
std::list<const Task*> sortedTaskList;
for (unsigned int i = 0; i < m_tasks.size(); i++)
sortedTaskList.push_back(&m_tasks[i]);
sortedTaskList.sort(compareTasksPtrBySumTime);
while (!sortedTaskList.empty()) //
{
const Task* taskPtr = sortedTaskList.back(); sortedTaskList.pop_back();
unsigned int taskNum = taskPtr->ordNum();
std::list<unsigned int>::iterator bestPosition = permutation.begin();
unsigned int bestTotalTime = std::numeric_limits<unsigned int>::max();
permutation.push_front(taskNum);
for (std::list<unsigned int>::iterator it = permutation.begin(); // szukanie najlepszej pozycji
it != permutation.end(); it++)
{
unsigned int currentTotalTime = calculateTotalTime(permutation, bestTotalTime);
if (bestTotalTime > currentTotalTime)
{
bestTotalTime = currentTotalTime;
bestPosition = it;
}
auto nextIt = it; nextIt++;
if (nextIt != permutation.end())
std::swap(*it, *nextIt);
}
totalTime = bestTotalTime;
permutation.insert(bestPosition, taskNum);
permutation.pop_back();
}
std::cout << "Ukonczono:" << name() << std::endl;
}
unsigned int Instance::calculateTotalTime(const std::list<unsigned int>& permutationList, unsigned int bestTimeFound) const
{
unsigned int rows = m_tasks[*permutationList.begin() - 1].machinesNum() + 1, columns = permutationList.size() + 1;
Matrix<unsigned int> matrix(rows, columns);
unsigned int totalTime = 0;
for (unsigned int c = 0; c < columns; c++)
matrix(0, c) = 0;
for (unsigned int r = 0; r < rows; r++)
matrix(r, 0) = 0;
std::list<unsigned int>::const_iterator it = permutationList.begin();
for (unsigned int c = 1; c < columns; c++)
{
unsigned int taskNum = *it;
for (unsigned int r = 1; r < rows; r++)
(matrix(r, c) = std::max(matrix(r, c - 1), matrix(r - 1, c)) + m_tasks[taskNum - 1].machineTaskTime(r));// >bestTimeFound;
// return std::numeric_limits<unsigned int>::max();
it++;
}
return matrix(rows - 1, columns - 1);
}
void Instance::readFromFile(std::istream& is)
{
int taskNum, machineNum;
is >> taskNum >> machineNum;
for (int i = 0; i < taskNum; i++)
{
Task task(i + 1);
task.readFromFile(is);
if (is)
m_tasks.push_back(task);
}
}
class InstanceVector
{
public:
void readFromFile(std::istream& is);
void neh(std::list< std::list<unsigned int> >& result) const;
void neh(std::ostream& os) const;
private:
std::vector<Instance> m_instances;
};
void InstanceVector::readFromFile(std::istream& is)
{
while (is)
{
std::string name;
is >> name;
Instance instance(name);
instance.readFromFile(is);
std::list<unsigned int> l;
unsigned int totalTime;
if (is)
m_instances.push_back(instance);
}
}
void InstanceVector::neh(std::list< std::list<unsigned int> >& results) const
{
std::vector<Instance>::const_iterator it;
for (it = m_instances.begin(); it != m_instances.end(); it++)
{
std::list<unsigned int> resultInstance;
unsigned int totalTimeInstance;
it->neh(resultInstance, totalTimeInstance);
results.push_back(resultInstance);
}
}
void InstanceVector::neh(std::ostream& os) const
{
std::list< std::list<unsigned int> > results;
for (std::vector<Instance>::const_iterator it = m_instances.begin();
it != m_instances.end(); it++)
{
std::list<unsigned int> resultInstance;
unsigned int totalTimeInstance;
it->neh(resultInstance, totalTimeInstance);
results.push_back(std::move(resultInstance));
}
for (std::list< std::list<unsigned int> >::const_iterator it = results.begin();
it != results.end(); it++)
{
for (std::list<unsigned int>::const_iterator itPermutation = it->begin(); itPermutation != it->end(); itPermutation++)
os << *itPermutation << " ";
os << std::endl;
}
}
int main(int argc, char* argv[])
{
InstanceVector instanceVec;
std::ifstream input("bench_fs.txt");
if (input.is_open())
instanceVec.readFromFile(input);
std::ofstream output("output.txt");
instanceVec.neh(output);
std::cin.get();
}
The time taken by your program dependent both on the code and the data. Without the data we can only guess at why your program is taking more time than you expected. I will hazard some guesses as to where time is being lost but first I will strongly encourage you to try measuring how your program is spending its time. On Linux you can use perf to measure where your program is spending its time but there are plenty of tools to chose from. This will help in two ways. First, the following guesses may be completely wrong. Second, you will know how to find the performance problems in your next program.
In the absence of any hard information my gut is wary of two elements of your program.
You are storing your permutation as a std::list and I suspect that traversal and modification of this list is taking more time than you are saving by having an efficient push_front(). Try switching to std::vector. You can avoid push_front() by doing a push_back() and reversing the direction you move the new task through the permutation and keeping a best permutation rather than best position.
Inside calculateTotalTime() the matrix object is allocating and deallocating memory each time. This is potentially adding up to a significant amount of time. You could pass the matrix as an argument to calculateTotalTime() and store the matrix object at a level where it will be allocated/deallocated far less frequently. You probably need to do as #PaulMcKenzie suggests and use std::vector in your matrix class, rather than unique_ptr, so that you can reserve capacity ahead of time.
Hope that helps.

Combination of lists by type algorithm

I'm attempting to create an algorithm in C++ which will give me all of the possible combinations of a set of list items (input in a map format). I want to avoid duplicates and make sure to cover all possible combinations. To simplify the example, here's what the input may look like:
map<string, vector<string> > sandwichMap;
sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");
I'd feed this map into the algorithm, and it should spit out a vector with all of the possible combinations (using one of each key type):
wheat+ham+lettuce+mustard
wheat+turkey+lettuce+mustard
wheat+roastbeef+lettuce+mustard
white+ham+lettuce+mustard
white+turkey+lettuce+mustard
white+roastbeef+lettuce+mustard
It needs to work for any map of string vectors. So far I've tried and gotten close, but I end up with duplicate combinations and missed combinations:
sandwichList getCombinations(sandwichMap sMap)
{
locList retList;
int totalCombos = 1;
for (sandwichMapIt i = sMap.begin(); i != sMap.end(); ++i)
{
totalCombos *= i->second.size();
}
retList.resize(totalCombos);
int locCount;
for (sandwichMapIt a = sMap.begin(); a != sMap.end(); ++a)
{
locCount = 0;
for (locListIt l = a->second.begin(); l != a->second.end(); ++l)
{
for (unsigned int i = 0; i < totalCombos / a->second.size(); ++i)
{
retList[i + a->second.size() * locCount] += *l;
}
locCount++;
}
}
return retList;
}
Any help would be greatly appreciated!
Updated code:
#include <vector>
#include <map>
#include <list>
#include <iostream>
typedef std::vector<std::string> strVec;
typedef std::list<std::string> strList;
typedef std::map<std::string, strVec> sandwichMap;
int main()
{
sandwichMap sMap;
sMap["bread"].push_back("wheat");
sMap["bread"].push_back("white");
sMap["meat"].push_back("ham");
sMap["meat"].push_back("turkey");
sMap["meat"].push_back("roastbeef");
sMap["veggie"].push_back("lettuce");
sMap["sauce"].push_back("mustard");
strList finalSandwichList;
for (sandwichMap::iterator i = sMap.begin(); i != sMap.end(); ++i)
{
strList tmpSandwich;
for (strVec::iterator j = i->second.begin(); j != i->second.end(); ++j)
{
if (finalSandwichList.empty())
{
tmpSandwich.push_back(*j);
}
else
{
for (strList::iterator k = finalSandwichList.begin(); k != finalSandwichList.end(); ++k)
tmpSandwich.push_back(*k + "+" + *j);
}
}
tmpSandwich.swap(finalSandwichList);
}
for (strList::iterator i = finalSandwichList.begin(); i != finalSandwichList.end(); ++i)
{
std::cout << *i << std::endl;
}
return 0;
}
//solution
std::list<std::string> result;
for(auto i=sandwichMap.begin(); i!=sandwichMap.end(); ++i) {
std::list<std::string> new_result;
for(auto j=i->second.begin(); j!=i->second.end(); ++j) {
if(result.empty())
new_result.push_back(*j);
else
for(auto k=result.begin(); k!=result.end(); ++k)
new_result.push_back(*k + "+" + *j);
}
new_result.swap(result);
}
This should work :
#include<iostream>
#include<map>
#include<string>
#include<algorithm>
using namespace std;
map<string, vector<string>> sMap;
vector<string> add;
int sett[200], countt;
void solve(map<string, vector<string>>::iterator itt, int ct, vector<string> addd){
vector<string> tmp = itt->second;
if(ct == countt){
for(int j=0;j<addd.size();j++){
cout<<addd[j]<<" ";
}
cout<<endl;
return;
}
itt++;
for(int i=0;i<tmp.size();i++){
//cout<<tmp[i]<<" ";
addd.push_back(tmp[i]);
solve(itt, ct+1, addd);
vector<string>::iterator tempIt = addd.end();
addd.erase(tempIt--);
}
}
int main(){
sMap["bre"].push_back("wh");
sMap["bre"].push_back("whi");
sMap["me"].push_back("ham");
sMap["me"].push_back("tur");
sMap["me"].push_back("rr");
sMap["veg"].push_back("let");
sMap["sau"].push_back("mus");
countt = sMap.size();
solve(sMap.begin(), 0, add);
return 0;
}
I have used backtracking to evaluate every possible combination.
Note : it is in c++11 you might need to change some part of the code for lower version of c++
link to output : http://ideone.com/Ou2411
The code is kinda long because of the helper methods, but it does the job:
#include <vector>
#include <string>
#include <map>
#include <iostream>
using namespace std;
template <class T>
vector<T> Head(const vector<T> &v) {
return vector<T>(v.begin(), v.begin() + 1);
}
template <class T>
vector<T> Tail(const vector<T> &v) {
auto first = v.begin() + 1;
auto last = v.end();
return vector<T>(first, last);
}
template <class T>
vector<T> Concat(const vector<T> &v1, const vector<T> &v2) {
vector<T> result = v1;
result.insert(result.end(), v2.begin(), v2.end());
return result;
}
vector<vector<string>> CombineVectorWithScalar(const vector<vector<string>> &v, const string &scalar) {
vector<vector<string>> result = v;
for (unsigned i = 0; i < v.size(); i++) {
result[i].push_back(scalar);
}
return result;
}
vector<vector<string>> CombineVectorWithVector(const vector<vector<string>> &v1, const vector<string> &v2) {
if (v2.empty()) {
return vector<vector<string>>();
}
else {
auto headCombination = CombineVectorWithScalar(v1, v2.front());
auto tailCombination = CombineVectorWithVector(v1, Tail(v2));
return Concat(headCombination, tailCombination);
}
}
vector<string> GetKeys(const map<string, vector<string>> &mp) {
vector<string> keys;
for (auto it = mp.begin(); it != mp.end(); ++it) {
keys.push_back(it->first);
}
return keys;
}
vector<vector<string>> CombineMapValues(const map<string, vector<string>> &mp) {
vector<string> keys = GetKeys(mp);
vector<vector<string>> result;
auto &firstVector = mp.begin()->second;
for (auto it = firstVector.begin(); it != firstVector.end(); ++it) {
vector<string> oneElementList;
oneElementList.push_back(*it);
result.push_back(oneElementList);
}
vector<string> restOfTheKeys = Tail(keys);
for (auto it = restOfTheKeys.begin(); it != restOfTheKeys.end(); ++it) {
auto &currentVector = mp.find(*it)->second;
result = CombineVectorWithVector(result, currentVector);
}
return result;
}
void PrintCombinations(const vector<vector<string>> & allCombinations) {
for (auto it = allCombinations.begin(); it != allCombinations.end(); ++it) {
auto currentCombination = *it;
for (auto itInner = currentCombination.begin(); itInner != currentCombination.end(); ++itInner) {
cout << *itInner << " ";
}
cout << endl;
}
}
int main() {
map<string, vector<string> > sandwichMap;
sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");
auto allCombinations = CombineMapValues(sandwichMap);
PrintCombinations(allCombinations);
return 0;
}
void generate_all(std::map<std::string,std::vector<std::string>>::iterator start,
std::vector<std::string::iterator> accomulator,
std::map<std::string,std::vector<std::string>>& sMap){
for (auto it=start; it!=sMap.end(); ++it){
for (auto jt=it->second.begin(); jt!=it->second.end(); jt++){
generate_all(start+1,accomulator.pus_back[jt],sMap);
}
}
if (accomulator.size() == sMap.size()){
// print accomulator
}
}
Call with generate_all(sMap.begin(),aVector,sMap);
If the map is too big to go recursively, you can always generate an equivalent iterative code.
This solution is not recursive. Basically what it does is the following:
Compute how many combinations are actually possible
Know that for each key in the map, you're going to have to add nrCombinations/nrItemsInKey of them in total.
You can see it as a tree growing, branching more and more the more keys you have visited.
If you keep track of how many there are, how spaced they are and where they start you can automatically fill all combinations.
Code
#include <vector>
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::vector<std::string> > sandwichMap;
sandwichMap["bread"].push_back("wheat");
sandwichMap["bread"].push_back("white");
sandwichMap["meat"].push_back("ham");
sandwichMap["meat"].push_back("turkey");
sandwichMap["meat"].push_back("roastbeef");
sandwichMap["veggie"].push_back("lettuce");
sandwichMap["sauce"].push_back("mustard");
sandwichMap["sauce"].push_back("mayo");
// Compute just how many combinations there are
int combinationNr = 1;
for ( auto it : sandwichMap ) {
combinationNr *= it.second.size();
}
std::vector<std::vector<std::string>> solutions(combinationNr);
// We start with empty lists, thus we only have one cluster
int clusters = 1, clusterSize = combinationNr;
for ( auto category : sandwichMap ) {
int startIndex = 0;
int itemsNr = category.second.size();
int itemsPerCluster = clusterSize / itemsNr;
for ( auto item : category.second ) {
for ( int c = 0; c < clusters; ++c ) {
for ( int i = 0; i < itemsPerCluster; ++i ) {
// We sequentially fill each cluster with this item.
// Each fill starts offset by the quantity of items
// already added in the cluster.
solutions[startIndex+i+c*clusterSize].push_back(item);
}
}
startIndex += itemsPerCluster;
}
clusters *= itemsNr;
clusterSize = combinationNr / clusters;
}
for ( auto list : solutions ) {
for ( auto element : list ) {
std::cout << element << ", ";
}
std::cout << "\n";
}
return 0;
}