Suppose I have a std::map<std::string,int> this map stores an id along with a debt amount.
I want to know if there was a way for me to obtain the 5 highest (int) values from the map.
I know I could iterate through the map and do a custom sort however is there a custom algorithm that might help me accomplish this ? What would the most efficient way be ?
Only if you save them in another place while inserting to the map and maintain it.
A map is just a map....
Getting the highest 5 will be o(N) on the map. if you manage them while inserting you can do it in o(1)
Create a map std::map<int, std::string> and insert all data from old map into this map.
Then 5 key from end of new map have the highest value.
you could build a vector of iterators into the map:
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
// make some data
using data_map_type = map<string, int>;
data_map_type data_map = {
{ "a", 10 },
{ "b", 5 },
{ "c", 3 },
{ "d", 3 },
{ "e", 4 },
{ "f", 1 },
{ "g", 2 },
{ "h", 5 },
{ "i", 0 },
{ "j", 2 },
{ "k", 1 },
};
// build reverse index (initially unordered)
std::vector<data_map_type::const_iterator> second_index;
for(auto it = begin(data_map) ; it != end(data_map) ; ++it)
second_index.push_back(it);
// order the secondary index by descending debt amount
sort(begin(second_index),
end(second_index),
[](const data_map_type::const_iterator& l,
const data_map_type::const_iterator& r)
{
return l->second > r->second;
});
// emit the top 5 (or fewer)
const auto limit = std::min(second_index.size(), size_t(5));
cout << "top " << limit << " entries:" << endl;
for(size_t i = 0 ; i < limit ; ++i)
{
cout << "key=" << second_index[i]->first << ", value=" << second_index[i]->second << endl;
}
return 0;
}
Related
I have a 2D array of chars of some rows and columns like unsigned char arr[rows][columns].
For example, let's assume rows = 10, columns = 10 and the array is filled up like so:
0 1 2 3 4 5 6 7 8
0: l m n
1: v g h k l Z a b d
2: M q r u v g h k l
3: M Q R Z a b d
4: M Q R d
5: d
There is no guarantee all rows and columns are filled up, and unfilled spaces are simply ignored.
I want to construct all possible 'words' of length 1 to max row, so in this case lengths 1 to 6, of all possible character combinations like such:
output:
len : 1
l
m
n
len 2:
lv
lg
lh
...
mv
mg
mn
...
len 3:
lvM
lvq
lvr
...
I tried to implement my other idea:
Yet another observation: For len == 2, you have to use all outputs for len == 1 and combining each with all characters of 2nd row. For len == 3, you have to use all outputs for len == 2, and combining each with all characters of 3rd row. And so on.
And this is what I got:
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> input = {
"lmn",
"vghk",
"Mqr"
};
std::cout << "output:\n";
// gather all combinations
std::vector<std::string> output;
// first row
std::cout << "len : 1\n";
const std::string& row0 = input.front();
for (char c : row0) {
output.emplace_back(1, c);
std::cout << c << '\n';
}
// other rows
for (size_t i = 1, n = input.size(); i < n; ++i) {
std::cout << "len : " << i + 1 << '\n';
const std::string& rowI = input[i];
const std::vector<std::string> outputPrev = std::move(output);
output.clear();
for (const std::string& textPrev : outputPrev) {
for (char c : rowI) {
output.emplace_back(textPrev + c);
std::cout << output.back() << '\n';
}
}
}
}
Output:
output:
len : 1
l
m
n
len : 2
lv
lg
lh
lk
mv
mg
mh
mk
nv
ng
nh
nk
len : 3
lvM
lvq
lvr
lgM
lgq
lgr
lhM
lhq
lhr
lkM
lkq
lkr
mvM
mvq
mvr
mgM
mgq
mgr
mhM
mhq
mhr
mkM
mkq
mkr
nvM
nvq
nvr
ngM
ngq
ngr
nhM
nhq
nhr
nkM
nkq
nkr
Live Demo on coliru
Here is the recursive version of the solution -- recursion based on the fact that the combinations of length n are just each item in a row concatenated on to all the combinations of length n-1 for all items in the row.
Note that n in the following is the zero-based index of the last row to include, so if you want all 6 character combinations that means n equals 5.
#include <vector>
#include <string>
#include <iostream>
std::vector<std::string> all_combinations(const std::vector< std::vector <std::string>>& rows, int n) {
if (n == 0)
return rows[0];
auto n_minus_one_combos = all_combinations(rows, n - 1);
const auto& row = rows[n];
std::vector<std::string> n_combos;
n_combos.reserve(n_minus_one_combos.size() * row.size());
for (const auto& ch : row) {
for (const auto& n_minus_one_combo : n_minus_one_combos) {
n_combos.push_back(n_minus_one_combo + ch);
}
}
return n_combos;
}
void main() {
std::vector< std::vector <std::string>> rows = {
{"l", "m", "n"},
{"v", "g", "h", "k", "l", "Z", "a", "b", "d"},
{"M","q","r","u","v", "g", "h", "k", "l"},
{"M","Q","R","Z","a","b","d"},
{"M","Q","R","d"},
{"d"}
};
for (const auto& combo : all_combinations(rows, 5)) {
std::cout << combo << "\n";
}
}
Normally the way to a good solution is
to first analyze the requirements and
then get an understanding of the mathematical background,
do the appropriate design,
using adequate C++ containers and elements
and at the very end, write the code
After analyzing the requirements, we find out that the mathematical background is to build a cartesian product of 2 sets.
The elements in the set are std::strings. We start with strings having only one character and build the cartesian product. The result is a strings with 2 characters, containing all possible combinations of the single characters.
For this task, building the cartesian product, is exceptionally simple. It is just a string concatenation of 2 elements. And with a std::string we can simply use the '+' operator for string concatention.
So, in C++ we can use 2 nested for loops like so:
for (const Element a : elements)
for (const Element b : B.elements)
cartesianProduct.elements.insert( a + b );
As a container for our elements, we can use one of the existing "sets" in the STL.
std::set having unique elements and is ordered
std::mulitset can have duplicate elements and is ordered
std::unordered_set having unique elements and is not ordered
std::unordered_mulitset can have duplicate elements and is not ordered
So, we mayselect any type of set, depending on our wish or requirements.
And since we are in C++ and do object oriented programming, we will wrap everthing in a class (struct) and overwrite 2 operators:
operator * for creating the cartesian product
operator << for simple output
So, if we change something within our class, the outer world will not be influenced. With that we can also use a std::vector to store the elements. No big deal at all.
And, for the implementation, we will add a special functionality for building the cartesian product. Normally the product of 2 sets, with at least one set being empty, will result in an empty set. But, because we want to do cartesian products for a whole set of sets, we want to start with an empty set and then build up all following sets in a loop.
And since in our case the cartesian product of 2 elements is a concatenation, so basically an addition, we can live with one set being empty (And a neutral element). Dear all mathematicians: Please show mercy and forgive me for doing that!
With all these preparations, we will build a very simple wrapper class and an even simpler and more intuitive "main" function. Please see one of many possible solutions below:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <set>
#include <unordered_set>
using Element = std::string;
using SetImplementation = std::unordered_set<Element>;
// Small wrapper to add additional functionality to our set
struct CSet {
SetImplementation elements{};
// Calculate the cartesian product
CSet operator * (const CSet& B) {
// Special handling. If one of the sets is empty, we return the other
if (elements.empty()) return B; if (B.elements.empty()) return *this;
// The resulting set containing the cartesian product
CSet cartesianProduct{};
// For all elements in set A and set B
for (const Element a : elements) for (const Element b : B.elements)
// For strings, the cartesian product is concatenation
cartesianProduct.elements.insert( a + b );
return cartesianProduct;
}
// Create the desired output for the set
friend std::ostream& operator << (std::ostream& os, const CSet& s) {
if (not s.elements.empty()) {
os << "Len: " << s.elements.begin()->size() << '\n';
std::copy(s.elements.begin(), s.elements.end(), std::ostream_iterator<Element>(os, "\n"));
}
return os;
}
};
// Test data
const std::vector<CSet> testSets{
{{"l", "m", "n"}},
{{"v", "g", "h", "k", "L", "Z", "a", "b", "d"}},
{{"M", "q", "r", "u", "v", "g", "h", "k", "l"}},
{{"M", "Q", "R", "Z", "a", "b", "d"}},
{{"M", "Q", "R", "d"}},
{{"d"}} };
// Driver Code
int main() {
CSet cartesianProduct{};
CSet& A{ cartesianProduct };
for (const CSet& B : testSets) {
cartesianProduct = A * B;
std::cout << cartesianProduct;
}
}
As said. You may use all kind of different sets. Simply change the using staement at the top, and it will continue to work.
And if you prefer to use a std::vector, then this is also possible. We will only modify class internals. Outside code stays as is. Please See the following piece of code:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using Element = std::string;
using SetImpl = std::vector<Element>;
struct Set {
std::vector<Element> elements{};
Set operator * (const Set& B) {
if (elements.empty()) return B;
if (B.elements.empty()) return *this;
Set cartesianProduct{};
cartesianProduct.elements.resize(elements.size() * B.elements.size());
auto product{ cartesianProduct.elements.begin() };
for (const Element a : elements) for (const Element b : B.elements)
*product++ = a + b;
return cartesianProduct;
}
friend std::ostream& operator << (std::ostream& os, const Set& s) {
if (not s.elements.empty()) {
os << "Len: " << s.elements[0].size() << '\n';
std::copy(s.elements.begin(), s.elements.end(), std::ostream_iterator<Element>(os,"\n"));
}
return os;
}
};
std::vector<Set> testSets{ {{"a","b"}}, {{"c"}}, {{"e", "f", "g"}} };
int main() {
Set cartesianProduct{}, &A{ cartesianProduct };
for (const Set& B : testSets) {
cartesianProduct = A * B;
std::cout << cartesianProduct;
}
}
#endif
#if 0
#include <iostream>
#include <cctype>
#include <climits>
#include <string>
#include <algorithm>
#include <iterator>
int main() {
// Loop. unitl the input number is valid
for (bool numberIsValid{}; not numberIsValid;) {
// Instruct user on what to do
std::cout << "\n\nEnter a number (digits only, no leading 0es) that you would like to reverse:\n";
// Read a number as string and check, if it is valid
if (std::string numberAsString{}; std::getline(std::cin, numberAsString) and
not numberAsString.empty() and
std::all_of(numberAsString.begin(), numberAsString.end(), std::isdigit) and
not (numberAsString[0] == '0') and
numberAsString.size() < std::numeric_limits<unsigned int>::digits10)
{
// Number is valid
numberIsValid = true;
std::cout << "\n\nReverse number is:\t ";
std::copy(numberAsString.rbegin(), numberAsString.rend(), std::ostream_iterator<char>(std::cout));
}
else {
std::cerr << "\nError: Invalid input\n\n";
}
}
}
Let's say I have the following object:
vector<string> data = {"12","12","12","12","13","14","15", "15", "15", "15", "18"};
I'm trying to find the first non-repeating entry in the data object.
For example, data.find_first_not_of(data.at(0)); this would work if data is of string type only (no container).
How can I achieve the same thing with an object of type vector.
I looked at adjacent_find and find_if_not from the algorithm library, but to no avail.
Your suggestions are much appreciated.
What problem did you have with adjacent_find? You should be able to use that with an inverse predicate:
std::vector<std::string> data = {"12","12","12","12","13","14","15", "15", "15", "15", "18"};
// Sort data here if necessary
auto itr = std::adjacent_find(data.cbegin(), data.cend(), std::not_equal_to<std::string>{});
if (itr != data.cend()) {
std::cout << "First mismatch: " << *itr << " " << *std::next(itr) << std::endl;
} else {
std::cout << "All elements equal" << std::endl;
}
Wandbox
Since you have to go through the list at least once, and you don't know when or where you will encounter the duplicate of a number (if there is one), one way to solve this is to first gather "statistics" and then from what you've gathered you can determine the first non-duplicate.
Here is an example using std::unordered_map:
#include <algorithm>
#include <unordered_map>
#include <iostream>
#include <vector>
#include <string>
// struct to hold some information on the numbers
struct info
{
std::string number;
int count;
int position;
info(const std::string n, int c, int p) : number(n), count(c), position(p) {}
};
int main()
{
std::vector<std::string> data = {"12","12","12","12","13","14","15", "15", "15", "15", "18"};
std::unordered_map<std::string, info> infoMap;
std::vector<info> vInfo;
int pos = 0;
// loop for each data element
std::for_each(data.begin(), data.end(), [&](const std::string& n)
{
// insert entry into the map
auto pr = infoMap.insert(std::make_pair(n, info(n, 0, pos)));
// bump up the count for this entry.
++pr.first->second.count;
// bump up the postion number
++pos;
});
// create a vector of the information with a count of 1 item.
std::for_each(infoMap.begin(), infoMap.end(), [&](std::unordered_map<std::string, info>::value_type& vt) { if (vt.second.count == 1) vInfo.push_back(vt.second); });
// sort this by position
std::sort(vInfo.begin(), vInfo.end(), [&](const info& pr1, const info &pr2){return pr1.position < pr2.position; });
// output the results
if ( vInfo.empty() )
std::cout << "All values are duplicated\n";
else
std::cout << "The first number that isn't repeated is " << vInfo.front().number << "\n";
}
Live Example
First, we just simply go through all the entries in the vector and just tally up the count for each item. In addition, we store the position in the original list of where the item was found.
After that we filter out the ones with a count of exactly 1 and copy them to a vector. We then sort this vector based on the position they were found in the original list.
I have a map defined as follows:
std::map<std::string, std::vector<std::pair<std::string, std::string>>> groupList;
GOAL:
I have a list of groups of commands. I want to sequence through each group in order. In order to do this, each group has a "sequence" value. I want to sort the overall list based on this value from smallest to largest. Essentially, I have a list of elements, which each have an accompanying list of other values within them specific to each parent. I want to sort the list of parents by a specific pair or value within the child lists.
For me to visualize this, I created an array in PHP with a similar structure. I'm not sure exactly how to visualize a C++ map so this is just me making assumptions. 1, 2, 3 are the keys of the map.
Array
(
[1] => Array
(
[groupID] => 1
[sequence] => 0
[command] => DefaultState
)
[2] => Array
(
[groupID] => 2
[sequence] => 2
[command] => Restart
)
[3] => Array
(
[groupID] => 3
[sequence] => 1
[command] => Beep
)
)
I'd like to sort this map based on the value of a particular pair inside, in this case "sequence". Element "2" should be below element "3" when sorting using the "sequence" value. The end result would look like this:
Array
(
[1] => Array
(
[groupID] => 1
[sequence] => 0
[command] => DefaultState
)
[3] => Array
(
[groupID] => 3
[sequence] => 1
[command] => Beep
)
[2] => Array
(
[groupID] => 2
[sequence] => 2
[command] => Restart
)
)
I'm sorry to mix languages here but there's no simple way for me to dump a map that depicts its structure (that I know of).
At first, my map was set up like so:
std::map<std::string, std::map<std::string, std::string>> groupList;
This was easier for me to add elements and then access them later, but I figured a vector pair would be easier to use for sorting. I would prefer to use the latter definition for ease. I was looking at using std::sort and boost but I've had no luck implementing for this specific case.
Any comments/help is welcome. Thanks!
Whenever I see a datastructure, I imagine to have a definition for it handy:
struct Item {
int groupID;
int sequence;
std::string command;
}
Now you can trivially define the array:
Item arr[] = {
{ 1, 0, "DefaultState" },
{ 2, 2, "Restart" },
{ 3, 1, "Beep" },
};
Since it's a simple aggregate with value semantics, you can just define an order and sort it:
struct Item {
int groupID;
int sequence;
std::string command;
bool operator<(Item const& other) const {
return sequence < other.sequence;
}
};
Demo
Adding a streaming operator<< and we get a full working demo:
Live On Coliru
#include <iostream>
struct Item {
int groupID;
int sequence;
std::string command;
bool operator<(Item const& other) const {
return sequence < other.sequence;
}
friend std::ostream& operator<<(std::ostream& os, Item const& i) {
return os << "Item { group:" << i.groupID << ", sequence:" << i.sequence << ", command:'" << i.command << "' }";
}
};
#include <algorithm>
int main() {
Item arr[] = {
{ 1, 0, "DefaultState" },
{ 2, 2, "Restart" },
{ 3, 1, "Beep" },
};
std::sort(std::begin(arr), std::end(arr));
for (auto& item : arr)
std::cout << item << '\n';
}
Prints
Item { group:1, sequence:0, command:'DefaultState' }
Item { group:3, sequence:1, command:'Beep' }
Item { group:2, sequence:2, command:'Restart' }
Expanding on my earlier answer, and in case you're really looking for something more advanced, here's what comes to mind using Boost MultiIndex containers:
Live On Coliru
#include <fstream>
#include <iostream>
struct Item {
int groupID;
int sequence;
std::string command;
friend std::ostream& operator<<(std::ostream& os, Item const& i) {
return os << "Item { group:" << i.groupID << ", sequence:" << i.sequence << ", command:'" << i.command << "' }";
}
};
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<
Item,
bmi::indexed_by<
bmi::ordered_unique<
bmi::tag<struct by_group>,
bmi::member<Item, int, &Item::groupID>
>,
bmi::ordered_unique<
bmi::tag<struct by_sequence>,
bmi::member<Item, int, &Item::sequence>
>
>
>;
#include <algorithm>
#include <map>
int main() {
Table arr = {
{ 1, 0, "DefaultState" },
{ 2, 2, "Restart" },
{ 3, 1, "Beep" },
};
for (auto& item : arr.get<by_group>())
std::cout << item << '\n';
std::cout << "\nsorted by sequence:\n";
for (auto& item : arr.get<by_sequence>())
std::cout << item << '\n';
}
Prints
Item { group:1, sequence:0, command:'DefaultState' }
Item { group:2, sequence:2, command:'Restart' }
Item { group:3, sequence:1, command:'Beep' }
sorted by sequence:
Item { group:1, sequence:0, command:'DefaultState' }
Item { group:3, sequence:1, command:'Beep' }
Item { group:2, sequence:2, command:'Restart' }
I cannot grasp the idea and programm such a thing correctly (I'm a beginner):
I have a vector. Vector has lets say elements: fieldA, fieldB, fieldC. So having array of these vectors, I want to check, beginning with the last vector in the array, and going to the direction of the first one, if one of the elements has a specific value, lets say if (vect[i].fieldA == 0.0). In such a case, if (vect[i-1].fieldA == 0.0) so has the same value, I want to remove the whole vector from array. Can someone provide me with a part of code that will visualize, how to create the proper "back iteration" loop and use function to delete it? I was trying with erase(), remove(), deque() but I failed.
I don't want to mess here with my codes.
Thanks for help!
EDIT. So I first fed in a loop my array with vectors values, then I want to remove all vectors from the end, that contain element specific value, e.g. fieldA == 0.0
I want to cut the array, not only remove content of vectors!
There is proper inheritance between classB and classA so the feeding works well, I want only to solve this thing with deleting the vectors.
example: array of vectors of 2 elements. input: 0,1 0,3 3,3 2,3 0,6 5,6 0,8 0,7 0,6 output:0,1 0,3 3,3 2,3 0,6 5,6 0,8. conclusion: 0,7 and 0,6 vectors were removed.
classA tmp;
for (std::vector<std::classB>::iterator iter = newW.begin(); iter != newW.end(); iter++)
{
tmp.set_fieldA(iter->a);
tmp.set_fieldB(iter->b);
tmp.set_fieldC(iter->c);
objA.push_back(tmp);
}
vector<std::classA> objA;
for(int i = objA.size()-1; i > 0; i--)
{
if (objA[i].fieldA == 0.0)
if (objA[i-1].fieldA == 0.0)
objA.erase(objA[i-1]); //remove last vector from array
}
I'm interpreting your code as follows. You have a struct named Vector with 3 members
struct Vector
{
double fieldA;
double fieldB;
double fieldC;
}
The code below works as follows. It uses std::find_if_not with reverse iterators (rbegin() and rend()) to find the first element from the back that has a fieldA different from 0. It then converts this to a regular iterator (using base()) and compares it to the end of the vector. Finally the call v.erase will actually erase them (the so-called erase-remove idiom)
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
int main()
{
struct Vector { int fieldA; int fieldB; };
std::vector<Vector> v = {
Vector{ 1, 0 }, Vector{ 2, 1 }, Vector{ 0, 2 }, Vector{ 1, 3 }, Vector{ 0, 4 },
Vector{ 0, 5 }, Vector{ 5, 6 }, Vector{ 6, 7 }, Vector{ 0, 8 }, Vector{ 0, 9 }, Vector{ 0, 10}
};
for (auto& e: v) { std::cout << "{" << e.fieldA << "," << e.fieldB << "}, "; };
std::cout << "\n";
auto m = std::find_if_not(v.rbegin(), v.rend(), [&](Vector const& elem){
return elem.fieldA == 0;
}).base();
if (m != v.end())
// remove all but one matching element
v.erase(m + 1, v.end());
for (auto& e: v) { std::cout << "{" << e.fieldA << "," << e.fieldB << "}, "; };
std::cout << "\n";
}
Output on LiveWorkSpace
What is the most efficient way to look up the adjacent elements in a STL map using the examples I mention below:
Suppose I have a map of integer - string:
1 -> Test1
5 -> Test2
10 -> Test3
20 -> Test4
50 -> Test5
If I call:
get_adjacent(1) // Returns iterator to 1 and 5
get_adjacent(2) // Returns iterator to 1 and 5
get_adjacent(24) // Returns iterator to 20 and 50
get_adjacent(50) // Returns iterator to 20 and 50
Use std::lower_bound and std::upper_bound for exactly this.
Better yet std::map::equal_range combines the power of both:
See it live on http://liveworkspace.org/code/d3a5eb4ec726ae3b5236b497d81dcf27
#include <map>
#include <iostream>
const auto data = std::map<int, std::string> {
{ 1 , "Test1" },
{ 5 , "Test2" },
{ 10 , "Test3" },
{ 20 , "Test4" },
{ 50 , "Test5" },
};
template <typename Map, typename It>
void debug_print(Map const& map, It it)
{
if (it != map.end())
std::cout << it->first;
else
std::cout << "[end]";
}
void test(int key)
{
auto bounds = data.equal_range(key);
std::cout << key << ": " ; debug_print(data, bounds.first) ;
std::cout << ", " ; debug_print(data, bounds.second) ;
std::cout << '\n' ;
}
int main(int argc, const char *argv[])
{
test(1);
test(2);
test(24);
test(50);
}
Outputs:
1: 1, 5
2: 5, 5
24: 50, 50
50: 50, [end]