I need to get the smallest element in a std::map. I'm aware that there is plenty of documentation available; however, I can't seem to get any to work.
I have two maps, bid and ask, both of which are properties of the Book class. Each is a map of queues. Each of these queues hold Order objects (which have various properties like price, volume, etc.). I have a member function update which obtains the best bid, best ask, and the spread:
void update(void)
{
unsigned long long highest_bid, lowest_ask = 0;
for (std::map<unsigned long long, queue<Order>>::iterator it = this->bid.begin(); it != this->bid.end(); ++it)
{
highest_bid = it->first;
}
// best ask code here
this->bestBid = highest_bid;
this->bestAsk = lowest_ask;
this->spread = labs(this->bestAsk - this->bestBid);
}
Where the ask code is, I've tried the following:
lowest_ask = this->ask.begin()->first;
This compiles, but when I debug it throws an assertion failure (which I've read up on other questions here and can't seem to understand):
Expression: map/set iterator not dereferencable
I've tried reverse iteration:
for(std::map<unsigned long long, queue<Order>>::reverse_iterator rit = this->ask.rbegin(); rit != this->ask.rend(); ++rit)
{
lowest_ask = rit->first;
}
Which compiles and debugs fine, but lowest_ask is always 0, which is wrong. When I step through it in the debugger it doesn't stop until it reaches zero.
I've tried swapping the iterators around:
for(std::map<unsigned long long, queue<Order>>::reverse_iterator rit = this->ask.rend(); rit != this->ask.rbegin(); ++rit)
{
lowest_ask = rit->first;
}
This compiled fine, but once again threw the debug assertion failure.
I could continue on and on on what I've tried, but this question is already over-complicated. I just don't understand why I can't just do what I did at the start (lowest_ask = this->ask.begin()->first).
Thank you very much in advance.
Iterating through the map and always assigning the same variable seems like needlessly hard work.
If you need to access the first item in the map (or the last item in the map) then begin() (or rbegin()) is all you need.
std::map <int, int> themap;
themap[4] = 1;
themap[2] = 2;
themap[1] = 3;
themap[6] = 4;
themap[5] = 5;
themap[7] = 6;
if (!themap.empty())
{
std::cout << "item[" << themap.begin()->first << "] = " << themap.begin()->second << std::endl;
std::cout << "item[" << themap.rbegin()->first << "] = " << themap.rbegin()->second << std::endl;
}
the only time you need to be careful with begin and rbegin is when your map is empty
I think you may just need to check that your containers are not empty so that begin() and rbegin() return something meaningful (defined).
Try this:
void update(void)
{
if(bid.empty() || ask.empty())
return;
// best ask code here
this->bestBid = bid.rbegin()->first;
this->bestAsk = ask.begin()->first;
this->spread = labs(this->bestAsk - this->bestBid);
}
This is not "complicated"; it simply takes some standard debugging measures
#include <map>
#include <iostream>
#include <algorithm>
#include <random>
#include <string>
#include <queue>
namespace mock {
using Order = std::string;
struct Book {
using key_type = unsigned long long;
using order_queue_type = std::queue<Order>;
using property_type = std::map<key_type, order_queue_type>;
property_type bids, asks;
void diagnose(const property_type& prop) {
for (auto it = prop.cbegin(); it != prop.cend(); ++it) {
std::clog << "\t" << it->first << '\n';
}
}
void diagnose() {
std::clog << "bids:" << '\n';
diagnose(bids);
std::clog << "asks:" << '\n';
diagnose(asks);
}
Book() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<key_type> ba_dist(0, 1000);
std::uniform_int_distribution<std::size_t> len_dist(0, 10);
auto prop_gen = [&] (property_type& prop) {
auto count = len_dist(gen);
for (std::size_t i = 0; i < count; ++i) {
auto val = ba_dist(gen);
auto pair = prop.emplace(val, order_queue_type());
if (!pair.second) {
std::clog << val << " already present" << '\n';
}
}
};
prop_gen(bids);
prop_gen(asks);
}
};
}
int main() {
mock::Book book;
book.diagnose();
}
Instead of the generator in my Book ctor, use your init routines, of course, and your Order type.
Related
#include <iostream>
#include <chrono>
#include <vector>
#include <algorithm>
template<class Type>
Type lnSearch(std::vector<Type>& Data, Type Target) {
for (typename std::vector<Type>::iterator Iterator = Data.begin(); Iterator != Data.end(); Iterator++) {
if (*Iterator == Target) return *Iterator;
else continue;
}
return Type{};
}
int main(void) {
std::vector<int> data;
for (int i = 0; i < 100000000; i++) {
data.push_back(i);
}
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
std::cout << lnSearch(data, 99999999);
std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
std::chrono::seconds sduration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
std::chrono::milliseconds msduration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
std::cout << "Time taken by function: " << sduration.count() << "." << msduration.count() << "s" << std::endl;
return 0;
}
Is my algorithm genuinely fast, is my clock coded incorrectly or is my perception of fast wrong?
in Release mode on vs22, it runs through 100,000,000 iterations in a range of 0.133s - 0.344s
Since the if statement in your code is very predictable, the processor can optimize this code very well.
An in depth explanation can be found here:
Why is processing a sorted array faster than processing an unsorted array?
This is what is expected.
Search 100,000,000 or 1e9 elements. Super simple.
Your CPU does about 1e10 things every second. (1)
So to find this operation is about 0.1 seconds is unsurprising.
[1] (I'm guessing you are on a modern desktop computer suitable for gaming).
Your optimizer would have change the code to either return 99999999 or return vector[99999999]
Either:
Run in debug, there will be a debug over-head but at least it wont change your code
Turn optimizer off around the code you want left alone "#pragma optimize( "[optimization-list]", {on | off} )"
Make a tonne of different vectors for the algorithm to work on so there isn't an obvious optimization
But running in debug where the optimizer hasn't changed this to just returning the value We have something like this, comparing it to a standard search algorithm.
#include <iostream>
#include <chrono>
#include <vector>
#include <algorithm>
template<class Type>
Type lnSearch(std::vector<Type>& Data, Type Target) {
for (typename std::vector<Type>::iterator Iterator = Data.begin(); Iterator != Data.end(); Iterator++) {
if (*Iterator == Target) return *Iterator;
else continue;
}
return Type{};
}
class Timer
{
private:
std::chrono::high_resolution_clock::time_point start;
public:
Timer()
{
start = std::chrono::high_resolution_clock::now();
}
~Timer()
{
std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
std::chrono::seconds sduration = std::chrono::duration_cast<std::chrono::seconds>(stop - start);
std::chrono::milliseconds msduration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
std::cout << "Time taken by function: " << sduration.count() << "." << msduration.count() << "s" << std::endl;
}
};
int main(void) {
const int size = 100000000;
const int valueToFind = 99999999;
std::vector<int> data;
data.reserve(size);
for (int i = 0; i < size; i++) {
data.push_back(i);
}
int* result = nullptr;
std::cout << "YOUR ALGORITHM\n";
{
Timer t1;
lnSearch(data, valueToFind);
}
std::cout << "\nBINARY SEARCH\n";
{
Timer t2;
if (std::binary_search(data.begin(), data.end(), valueToFind)){
}
}
return 0;
}
Which running on my computer outputs:
YOUR ALGORITHM
Time taken by function: 65.65407s
BINARY SEARCH
Time taken by function: 0.0s
Definitely recommend reading some search and sort algorithm strategies that lets you do smart things with your data. Binary search only works if it's a sorted list, like the one in your example.
Checking every element like you are is basically the slowest way to search for an item. Your code needs to check 99999999 elements,
binary search only checks 23:
i'm new to C++. My program is a quiz game which user can choose category and level for the questions. At first, i use the struct data type
struct QuestionInfo
{
string category;
string level;
string question;
string answer;
};
then
vector<QuestionInfo> vec;
The idea of this part is to store the info of the question include (category, level, question and answer) to each element.
Then after building menu and the output questions UI, i go to the filters
void category_filter()
{
for (unsigned int i = 0; i < vec.size(); i ++)
{
if (category_choice != vec[i].category)
vec.erase(vec.begin() + i );
}
}
Void level_filter()
{
for (unsigned int i = 0; i < vec.size(); i ++)
{
if (level_choice != vec[i].level)
vec.erase(vec.begin() + i );
}
}
So the idea of the filters is to delete the elements which not contain the matched category and level. But the output questions did not match with the category and the level i had choose before. I'm not sure what I'm doing wrong.
Let me explain you the problem with my example. Suppose you have a vector of 10 elements, valid indexes are 0 till 9 elements. You have to erase 5th element i == 4. You erase it, then 6th element with index 5 moves to place of 5th elements with index 4. After that you increase i in for, it becomes 5. Thus you skip previous 6th element, that is now 5th with index 4.
You may fix your code like below, moving i ++ to the condition.
for (unsigned int i = 0; i < vec.size(); ) {
if (category_choice != vec[i].category)
vec.erase(vec.begin() + i );
else
i ++;
}
The preferable solution in C++ way is demonstrated by #Jonathan.
You're getting tripped up by not accounting for the indexing shift that occurs when you erase an element. I personally would rely on remove_if and erase with a lambda to accomplish this:
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return category_choice != i.category; }, end(vec));
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return level_choice != i.level; }, end(vec));
Alternatively you might consider combining them for a bit of speed improvement:
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return category_choice != i.category || level_choice != i.level; }, end(vec));
You might want to remove_if + erase:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
struct QuestionInfo
{
std::string category;
std::string level;
std::string question;
std::string answer;
QuestionInfo(std::string category, std::string level, std::string question, std::string answer) :
category(category), level(level), question(question), answer(answer) {}
};
std::vector<QuestionInfo> vec;
std::string category_choice = "cat1";
std::string level_choice = "lev1";
vec.push_back(QuestionInfo("cat1", "lev1", "q1", "a1"));
vec.push_back(QuestionInfo("cat1", "lev2", "q2", "a2"));
vec.push_back(QuestionInfo("cat2", "lev1", "q3", "a3"));
vec.push_back(QuestionInfo("cat2", "lev2", "q4", "a4"));
std::cout << "\nNot filered" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
auto filter_category = std::remove_if(vec.begin(), vec.end(), [&](auto const &info) {return category_choice != info.category; });
vec.erase(filter_category, vec.end());
std::cout << "\nFilered by category" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
auto filter_level = std::remove_if(vec.begin(), vec.end(), [&](auto const &info) {return level_choice != info.level; });
vec.erase(filter_level, vec.end());
std::cout << "\nFiltered by level" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
system("pause");
return 0;
}
As mentioned by others, the remove_if + erase is a standard and expressive way to achieve what you want. But you may also consider non-destructive filtering with a copy_if into a new container, or even without using any additional storage with Boost.Range adaptor boost::adaptors::filtered or boost::filter_iterator. Look here for examples.
I want to find indices of an array that equal with specific value. so i've Written this code:
vector<int> _classes = { 2,2,1,1,3,3,3,3,5,5,4,4,5,6,6 };
vector<int> labelVec = {1,2,3,4,5,6};
vector<int> index;
for (int i = 0; i < labelVec.size(); i++)
{
compare(_classes, labelVec[i], index, CMP_EQ);
std::vector<int>::iterator nn = find(index.begin(), index.end(), 255);
}
but i have this error : Unhandled exception at 0x760B5608 in compareFuncTest.exe: Microsoft C++ exception: cv::Exception at memory location 0x004DDC44. if i define index as Mat, this problem will be resolved. but if i define index as Mat, i can't use from find(). also in this documentation states: output array (in my code as index) that has the same size and type as the input arrays. PLZ help me to fix this code.
I still do not get what is the point of this test, I guess this will be in some other algorithm... So, I give you two possible solutions.
1) Without OpenCV
First, you must know that
std::vector<int>::iterator nn = find(index.begin(), index.end(), 255);
Will only give you the first occurrance. Knowing this, here is a way you could check if the label is inside the _classes vector.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> _classes = { 2,2,1,1,3,3,3,3,5,5,4,4,5,6,6 };
std::vector<int> labelVec = {1,2,3,4,5,6,7};
for (const auto& label: labelVec)
{
std::vector<int>::iterator nn = find(_classes.begin(), _classes.end(), label);
if (nn != _classes.end())
{
std::cout << "I got the value from _classes: " << *nn << std::endl;
} else
{
std::cout << "I couldn't find the value with label:" << label << std::endl;
}
}
}
Here I iterate over all the labels (as you did) and then use the find directly in the classes, but with the label variable. Then I check if I found the label or not, if not, it will give you a value equal to _classes.end() which will give error if you try to use it (look at the extra label 7 which is not found).
This example can be tested here online.
2) With OpenCV
no oline test here. But this one is also easy to do. If you have a Mat in index you will only need to change the iterators to be templated. Like this:
auto nn = find(index.begin<int>(), index.end<int>(), 255);
If you a cv::Mat of classes you can also do it as in the method before and skip the comparison part (this would be faster)
Update
Since you want is the indices and all of them, then you have to iterate over it :/ if you wanted the values you could have used copy_if. You can create a lambda function to easily do the job.
like this:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
auto getIndices = [](const std::vector<int>& vec, const int value){
std::vector<int> result;
for (size_t t = 0; t < vec.size(); t++)
{
if (vec[t] == value)
{
result.push_back(static_cast<int>(t));
}
}
return result;
};
std::vector<int> _classes = { 2,2,1,1,3,3,3,3,5,5,4,4,5,6,6 };
std::vector<int> labelVec = {1,2,3,4,5,6,7};
for (const auto& label: labelVec)
{
std::vector<int> nn = getIndices(_classes, label);
std::cout << "I got the following indices for value"<< label<< ": [ ";
for (const auto& n : nn)
{
std::cout << n << ",";
}
std::cout << " ]" << std::endl;
}
}
I am trying to setup a map of map structure in C++ but can't make it work as expected. I put together this sample program to illustrate the issue. Please excuse the mess if it seems convoluted but I want to preserve the case as much as I can.
So the current print out is: L1, size = 0
and what I was expecting is something like:
L1, size 1
L2, 4
It seems like the second level map is not established properly, maybe a scoping issue, but I can't quite figure it out. The program is as the following:
// So the map is
// AKEY -> { BKEY -> [ SegPair, SegPair .... ] }
#include <map>
#include <utility>
#include <iostream>
#include <vector>
typedef std::string AKEY;
typedef std::string BKEY;
typedef std::pair<int,int> SegPair;
typedef std::vector<SegPair> SegVec;
typedef std::map<BKEY, SegVec> Ensemble;
typedef std::map<AKEY, Ensemble> Oracle;
using std::string;
Oracle o = Oracle();
void setup(string akey, string bkey, int x, int y) {
auto pos = o.find(akey);
if (pos == o.end()) {
o[akey] = Ensemble();
}
Ensemble e = o[akey];
auto pos2 = e.find(bkey);
if (pos2 == e.end()) {
e[bkey] = SegVec();
}
SegPair p(x, y);
e[bkey].push_back(p);
}
int main(void) {
setup("L1", "L2", 3, 4);
for (auto it = o.begin(); it != o.end(); it++) {
std::cout << it->first;
Ensemble e = it->second;
std::cout << ", size = " << e.size() << "\n";
for (auto it2 = e.begin(); it2 != e.end(); it2++) {
std::cout << "\t" << it2-> first << "\n";
SegVec v = it2->second;
for (int i = 0; i < v.size(); i++)
std::cout<< v[i].second << " ";
}
}
}
I think your problem is with this line:
Ensemble e = o[akey];
You're creating a local, rather than capturing the lvalue in the map by reference, for mutation. Thus, any changes you make to e after that point will simply be discarded when e goes out of scope.
In setup, e is a copy of the object in o.
When you modify it, you're not modifying anything in o.
To fix, use a reference:
Ensemble& e = o[akey];
That will make e refer to the same thing as o[akey] instead of a copy.
I have two questions but they are interlinked.:
part:a->
I have been trying to display the elements of vector in reverse order. But nothing is working. I have used iterotar like;
for (it=vec.end(); it!=vec.begin(); --it){
// it is iterator not reverse_iterator.
// do work
}
P.S I am not much familiar with iterators. I have used them for the first time today to
display elem in reverse order.
also tried;
for (int i=vec.size(); i!=0; i--){
//display
}
No matter what I do it always display the elem in same order as they are present i.e not in the reverse order.
part_b->
Is there any way that I can store the output of a recursive function direct into a vector. like the code is:
I know this does not work. I have tried but just giving you an idea
what I am upto.
#include <iostream>
using namespace std;
#include "vector"
int func(int num);
vector <int> vec;
int main() {
int num=34;
// I know this would not work. But is there any possibilitiy that
// I can store the output in a vector.
vec = binary(num);
// trying to display the vector.
for (int i=vec.size();i!=0;i--) {
cout<<vec[i]<<" ";
} // not working for reverse display.
} //main.
int func(int num) {
if (num==1) {
//vec.push_back(1);
return 1;
}
else if(num==0) {
//vec.push_back(0);
return 0;
}
else {
//vec.push_back(input%2);
return binary(input/2);
}
} //func.
I hope you do unnderstand the question. if I am able to do the part b the there is no need to reverse the elem of the vector.
The standard solution uses reverse iterators:
for (auto it = v.rbegin(); it != v.rend(); ++it)
{
if (it != v.rbegin()) { std::cout << ' '; }
std::cout << *it;
}
Alternatively, you can use indices, but keep the "reversal" idiom and increment the index:
for (std::size_t i = 0; i != v.size(); ++i)
{
if (i != 0) { std::cout << ' '; }
std::cout << v[v.size() - i - 1];
}
Note that reverse iterators are literally just doing something very similar to the explicit loop under the hood. In particular, the base() member function of a reverse iterator gives you the corresponding ordinary iterator offset by one, just as we have a - 1 in the index computation. (E.g. rbegin() is just end() under the hood, but decrements by one upon dereferencing.)
Use reverse iterators:
for (auto it = vec.crend(); it != vec.crbegin(); ++it) {
std::cout << *it << ' ';
}
std::cout << '\n';
Part A
Assuming you haven't got access to C++11:
vector<int>::const_reverse_iterator it;
for (it=vec.rbegin(); it!=vec.rend(); ++it)
{
// do work
}
Part B
It looks very much like you're trying to display a number in binary. Unfortunately the standard flags on ostream only allow hex, decimal or octal as far as I'm aware, but can I suggest a simpler way of doing this?
#include <bitset>
bitset< sizeof(int) << 3 > b(34);
cout << b << endl;
Which gives:
00000000000000000000000000100010
The rather ugly looking sizeof(int) << 3 is just a way of getting the size of an int in bits to avoid truncation.
I wrote little program which may help. Maybe your vector is empty?
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> vec;
vec.insert(vec.begin(), 1, 1);
vec.insert(vec.begin(), 1, 2);
vec.insert(vec.begin(), 1, 3);
vector<int>::iterator i;
for (i = vec.end(); i != vec.begin(); --i)
{
cout << *i;
}
cout << *i;
return 0;
}