changing key values of all elements in a multimap container [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am working on a c++ code which includes a command schedule. I implement the schedule as a multimap container, with execution time,as the key, and command name I want to execute. I need to be able to time shift all the commands in the schedule.
I assume I can do that by copying the container to another container and erasing the original container, then changing the key values for each pair in the copy container and inserting it back in the original container, like the example code below.
#include <stdio.h>
#include <map>
int main() {
std::multimap<int,int> original,copy;
original.insert(std::pair<int,int>(10,1));
original.insert(std::pair<int,int>(10,2));
original.insert(std::pair<int,int>(12,3));
std::multimap<int,int>::iterator it;
copy=original;
it=original.begin();
original.erase(it,original.end());
int tctime;
int command;
for (it=copy.begin();it!=copy.end();it++){
tctime =(*it).first+5;
command=(*it).second;
original.insert(std::pair<int,int> (tctime, command));
}
return 0;
}
while this works, I would like to know if there is a better solution to implement it.

Although you should ask these kind of questions on Code Review, I will write my answer here also so it may help someone else (and since it is not yet closed).
First, since your question has a C++ tag, please use #include <iostream> instead of #include <stdio.h>.
Second, I suggest you to use std::make_pair instead of the std::pair constructor. std::make_pair automatically deduces types of the values passed to it so I would prefer it over std::pair where you need to specify the types. So, you should use something like this:
original.insert(std::make_pair(10,1));
Next, since you are erasing all the values from the std::multimap<int,int> original, why not just use std::multimap::clear? It is less code to write and your intention is more straightforward.
original.clear()
instead of
it=original.begin();
original.erase(it,original.end());
Furthermore, I would suggest using range-for loops over the standard loops.
for (auto const& it : copy) {
tctime = it.first +5;
command = it.second;
original.insert(std::make_pair(tctime, command));
}
instead of
for (auto it = copy.begin(); it != copy.end(); it++){
tctime =(*it).first+5;
command=(*it).second;
original.insert(std::pair<int,int>(tctime, command));
}
And the last thing, good practice would be to initialize variables tctime and command to 0.
Full code:
#include <iostream>
#include <map>
int main() {
std::multimap<int,int> original,copy;
original.insert(std::make_pair(10,1));
original.insert(std::make_pair(10,2));
original.insert(std::make_pair(12,3));
copy=original;
original.clear();
int tctime = 0;
int command = 0;
for (auto const& it : copy) {
tctime = it.first +5;
command = it.second;
original.insert(std::make_pair(tctime, command));
}
return 0;
}
Here is the fully refactored code live.

Related

How can I convert a vector iterator to an int value to print it? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I keep getting an error while running this code. I've searched for a solution for similar errors, but as a junior programmer, I can't understand solutions meant to be for different codes.
Here is my code. Please give me a solution with demonstration.
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;
int main() {
vector <int> listed_elements {10,6,11};
auto min_value = min_element(listed_elements.begin(), listed_elements.end());
cout << "The smallest element on the list is: ";
cout << min_value << endl;
return 0;
}
Iterators mimick pointers. You can dereference the iterator to get the element:
cout << *min_value << endl;
Note that in general algorithms often return end (the iterator you passed as second parameter) to signal that no element was found and then you need to check that you have a valid iterator before dereferencing it:
if (min_value != listed_elements.end()) {
std::cout << *min_value << std::endl;
}
However, the only case where std::min_element returns the end iterator is when the range is empty, so in case you are absolutely certain that this isn't the case you can drop that check (but only then!).

Can we get an iterator that filters a vector from a predicate in C++?

Is it possible to get an iterator over a vector that filters some element with a predicate, i.e. showing a view of the vector?
I think remove_if does something similar but I have not found whether I can use it as I want to or not.
Something like:
auto it = filter(vec.begin(), vec.end(), predicate);
// I can reuse the iterator like:
for (auto i = it; i != vec.end(); i++)
// ...
Edit: (A bit more context to get the best answer) I am doing a lot of queries in an sqlite database of log data in order to print a report.
The performances are not good at the moment because of the number of request needed. I believe querying once the database and storing the result in a vector of smart pointers (unique_ptr if possible), then querying the vector with pure C++ may be faster.
Using copy_if is a good way to do the queries, but I don't need to copy everything and it might cost too much at the end (not sure about that), I should have mentioned than the data are immutable in my case.
As #Jarod42 mentioned in the comments one solution would be using ranges:
#include <algorithm>
#include <iostream>
#include <vector>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
int main()
{
std::vector<int> numbers = { 1, 2, 3 ,4, 5 };
auto predicate = [](int& n){ return n % 2 == 0; };
auto evenNumbers = numbers | ranges::view::filter(predicate);
auto result = numbers | ranges::view::filter(predicate)
| ranges::view::transform([](int n) { return n * 2; });
for (int n : evenNumbers)
{
std::cout << n << ' ';
}
std::cout << '\n';
for (int n : result)
{
std::cout << n << ' ';
}
}
evenNumbers is a range view adapter which sticks to the numbers range and changes the way it iterates.
result is a ranges of numbers that have been filtered on the predicate and then have been applied a funciton.
see the compile at compiler-explorer
credit: fluentcpp
Your question
Can we get an iterator that filters a vector from a predicate in C++?
in the sense you are asked it, can only be answered with: No. At the moment not (C++17). As per your requirement the iterator then would have to store the predicate and checking that for each modification of the position or for all dereferencing stuff. I.e before any dereferencing, the predicate would need to be checked. Because other code could modifiy your std::vector. The the iterator would need to check the predicate all the time. Also standard functionality like begin, end, distance would be rather complicated.
So you could create your own iterator by deriving from an existing iterator. Store the predicate and overload most of the functions to take care of the predicate. Very, very complicated, much work and maybe not, what you want to have. This would be the only way to get exact your requested functionality.
For work arounds, there are are many other possible solutions. Peolple will show you here.
But if I read your statement
"showing a view of the vector"
then life becomes easier. You can easily create a view of a vector by copying it conditionally with std::copy_if, as oblivion has written. That is in my opinion the best answer. It is none destructive. But it is a snapshot and not the original data. So, it is read only. And, it does not take into account changes to the original std::vector after the snapshot has been taken.
The second option, a combination of std::remove_if and std::erase, will destroy the original data. Or better said, it will invalidate the filtered out data. You could also std::copy_if the unwanted data to a backup area, std::remove_if them, and at the end add them again to the vector.
All these methods are critical, if the original data will be modified.
Maybe for you the standard std::copy_if is best to create a view. You would then return an iterator of copy and work with that.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> testVector{ 1,2,3,4,5,6,7 }; // Test data
std::vector<int> testVectorView{}; // The view
// Create predicate
auto predForEvenNumbers = [](const int& i) -> bool { return (i % 2 == 0); };
// And filter. Take a snapshot
std::copy_if(testVector.begin(), testVector.end(), std::back_inserter(testVectorView), predForEvenNumbers);
// Show example result
std::vector<int>::iterator iter = testVectorView.begin();
std::cout << *iter << '\n';
return 0;
}
Please note. For big std::vectors, it will become a very expensive solution . . .

initilize unordered_map with a vector in c++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I simply would like to initizlize an unordered_map with a vector.
When I have tried the code below, the code does not compile.
What is the shortest syntax to initilize unordered_map with a vector? How would you implement following method without using loop.
unordered_map<int, int> convertToMap(const vector<int>& v)
{
unordered_map<int, int> umap(v.begin(), v.end());
return umap;
}
I have found some resources, and I have tried to initialize through a range, but it does not worked either!
initialize-unordered-map
How to initialize unordered_map with vector?
If your vector contains pairs of elements, so that one could be interpreted as key and one as value then you can use range initialization:
#include <vector>
#include <unordered_map>
#include <iostream>
#include <utility>
int main()
{
std::vector<std::pair<int, int>> v = { {1,10}, {2,20}, {3,30} };
std::unordered_map<int, int> map(v.begin(), v.end());
std::cout << map[2] << std::endl;
return 0;
}
The above prints: 20

Extract vector from std::map<int, std::vector> [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
Here is my code
#include <iostream>
#include <map>
#include <string>
#include <vector>
typedef std::vector<int> VectorInt;
typedef std::map<int, VectorInt> MapVectorInt;
int main() {
MapVectorInt myMap;
VectorInt v1;
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
VectorInt v2;
v2.push_back(2);
v2.push_back(4);
v2.push_back(6);
myMap.insert(std::make_pair(0, v1));
myMap.insert(std::make_pair(1, v2));
return 0;
}
What is the bese way to take (extract/get) the vector at position x (eg 1,2...);
You can use:
auto v1=myMap[0]; //This will do a deep copy for the vector
or:
auto& v1=myMap[0]; //This will hold a reference to the vector
Be careful in the second approach because if the item has removed , the reference will be invalid.
If you want a safe option use std::map::at:
auto v1=myMap.at(0);
or:
auto& v1=myMap.at(0)
This will throw an exception (std::out_of_range) if the item is not there.
Short answer:
Best place to look for it http://en.cppreference.com/w/cpp/container/map/find
With context:
For visualisation only, I guess you should express you intention as you said in your question(get an element from the map and not "eventually" insert it as using [] for accessing a non-existing element creates it), so:
const auto& search = myMap.find(1);
if (search != example.end()) {
for(auto value: search->second) {
std::cout << value << '\n';
}
}
else {
std::cout << "Not found\n";
}
Try It Live
You can refer to the vector in the map with myMap[0] or myMap[1].
You could make an alias for either of those, e.g. auto& x = myMap[0];. Using the alias will access the vector as it is stored in the map.
To take a copy of the vector (so that you can modify the map contents without changing the copy), it is just the same as copying any other object:
auto x = myMap[0];
Note that 0 and 1 refer to the key you used in the insert call; not to the search order or the insertion order (although in your example those things all happen to be the same).

How to set values in C++ template object? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am trying to create a template class that will allow me to print the contents of an object, however, being new to this, I am struggling to set the values of the data.
If, for example, I have a template that takes two typename parameters, how would I go about setting the values? Must I treat every instance of a template in a similar manner to an array or vector?
Pair<int, double> first, second;
Obviously first = 10 does not work. What am I doing wrong?
You create two Pair objects, so you cannot assign 5 to one of them, since 5 is not a Pair.
Pair<int, double> first, second; // means that you have TWO pairs!
// it was equal to:
// Pair<int, double> first;
// Pair<int, double> second;
first.first = 5;
first.second = 3.14f;
second.first = 3;
second.second = 7.421f;
You probably wanted something like this:
Pair<int, double> myPair; // only 1 pair
myPair.first = 5;
myPair.second = 3.14f;
Hopefully you are using std::pair and not writing your own pair class.
other than what has already been answered to you, you must also be familliar with std::make_pair which creates a pair and deducts the types from the arguments, thus making your code smaller and more readable.
example:
auto myPair = std::make_pair(4,5.6);