How to change a vector item in C++? - c++

I've got a vector of structs in C++ and I would like to modify each item individually. I found that doing SomeStruct info = myVector[i] gives me a copy of the item, so if I modify it nothing will be changed. So right now I'm resetting the item like that: myVector[i] = info. Is there a more efficient way do that? One that won't involve a copy operation?
This is my current code:
struct CharacterInfo {
QChar character;
int occurrences;
double frequency;
};
std::vector<CharacterInfo> characterInfos;
// Some code to populate the vector
for (unsigned i = 0; i < characterInfos.size(); i++) {
CharacterInfo info = characterInfos[i];
info.frequency = (double)info.occurrences / (double)totalOccurrences;
characterInfos[i] = info; // how to avoid this?
}

The simplest way which doesn't change too much of your code is just to use a reference instead of an instance. So:
SomeStruct & info = myVector[i];
The next easiest way is to change from using a loop with an index, so like:
for (std::vector<SomeStruct>::iterator it = myVector.begin(); it != myVector.end(); ++it)
{
SomeStruct & info = *it;
// do stuff here
}
With the STL you can go even further, especially if you have a C++11 capable compiler, for instance:
std::for_each(std::begin(myVector), std::end(myVector), [](SomeStruct & info) { /* do stuff here */ });
Also not related to your question directly, but if you add a method to the struct that computes the frequency, the code becomes much cleaner, for instance following from the last example you could do:
std::for_each(std::begin(myVector), std::end(myVector), std::mem_fun(&SomeStruct::calculateFrequency));
This will also work without a C++11 compiler if you change the calls to std::begin(myVector) with myVector.begin() and the same for end.

You can use a reference:
CharacterInfo& info = characterInfos[i];
info.frequency = (double)info.occurrences / (double)totalOccurrences;
The reference info is bound to the element of your vector. If you change it, you change
the vector element too.

You could iterate through the vector with an STL iterator:
for (vector<CharacterInfo>::iterator it = characterInfos.begin();
it != characterInfos.end(); ++it) {
it->frequency = (double)it->occurrences / totalOccurrences;
}
In the loop, it is an iterator that has basically same functionality and interface as a pointer to a CharacterInfo struct: http://cplusplus.com/reference/std/iterator/RandomAccessIterator/
Looping with an iterator is the more idiomatic way of iterating through each element of a std::vector if you don't need to know the index of each element.

I am not sure I understand your question but I think you are trying to do this?
for (unsigned i = 0; i < characterInfos.size(); i++) {
characterInfos[i].frequency = (double)characterInfos[i].occurrences / (double)totalOccurrences;
}
Another option would be to use iterators:
for(std::vector<CharacterInfo>::iterator it = characterInfos.begin(); it != characterInfos.end(); ++it){
it->frequency = (double)it->occurences / (double)totalOccurences;
}

Wow, this is a very old question. For "newer" c++, the same can be done with Range-based for loop (since C++11)
for(auto &characterInfo : characterInfos) {
characterInfo.frequency = characterInfo.occurences / static_cast<double>(totalOccurences);
}

Related

C++ LRU cache - need suggestions on how to improve speed

The task is to implement an O(1) Least Recently Used Cache
Here is the question on leetcode
https://leetcode.com/problems/lru-cache/
Here is my solution, while it is O(1) it is not the fastest implementationcould you give some feedback and maybe ideas on how can I optimize this ? Thank you !
#include<unordered_map>
#include<list>
class LRUCache {
// umap<key,<value,listiterator>>
// store the key,value, position in list(iterator) where push_back occurred
private:
unordered_map<int,pair<int,list<int>::iterator>> umap;
list<int> klist;
int cap = -1;
public:
LRUCache(int capacity):cap(capacity){
}
int get(int key) {
// if the key exists in the unordered map
if(umap.count(key)){
// remove it from the old position
klist.erase(umap[key].second);
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
umap[key].second = --key_loc;
return umap[key].first;
}
return -1;
}
void put(int key, int value) {
// if key already exists delete it from the the umap and klist
if(umap.count(key)){
klist.erase(umap[key].second);
umap.erase(key);
}
// if the unordered map is at max capacity
if(umap.size() == cap){
umap.erase(klist.front());
klist.pop_front();
}
// finally update klist and umap
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
umap[key].first = value;
umap[key].second = --key_loc;
return;
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
Here's some optimizations that might help:
Take this segment of code from the get function:
if(umap.count(key)){
// remove it from the old position
klist.erase(umap[key].second);
The above will lookup key in the map twice. Once for the count method to see if it exists. Another to invoke the [] operator to fetch its value. Save a few cycles by doing this:
auto itor = umap.find(key);
if (itor != umap.end()) {
// remove it from the old position
klist.erase(itor->second);
In the put function, you do this:
if(umap.count(key)){
klist.erase(umap[key].second);
umap.erase(key);
}
Same thing as get, you can avoid the redundant search through umap. Additionally, there's no reason to invoke umap.erase only to add that same key back into the map a few lines later.
Further, this is also inefficient
umap[key].first = value;
umap[key].second = --key_loc;
Similar to above, redundantly looking up key twice in the map. In the first assignment statement, the key is not in the map, so it default constructs a new value pair thing. The second assignment is doing another lookup in the map.
Let's restructure your put function as follows:
void put(int key, int value) {
auto itor = umap.find(key);
bool reinsert = (itor != umap.end());
// if key already exists delete it from the klist only
if (reinsert) {
klist.erase(umap[key].second);
}
else {
// if the unordered map is at max capacity
if (umap.size() == cap) {
umap.erase(klist.front());
klist.pop_front();
}
}
// finally update klist and umap
klist.push_back(key);
list<int>::iterator key_loc = klist.end();
auto endOfList = --key_loc;
if (reinsert) {
itor->second.first = value;
itor->second.second = endOfList;
}
else {
const pair<int, list<int>::iterator> itempair = { value, endOfList };
umap.emplace(key, itempair);
}
}
That's as far as you can probably go by using std::list. The downside of the list type is that there's no way to move an existing node from the middle to the front (or back) without first removing it and then adding it back. That's a couple of unneeded memory allocations to update the list. Possible alternative is that you just use your own double-linked list type and manually fixup the prev/next pointer yourself.
Here is my solution, while it is O(1) it is not the fastest implementation
could you give some feedback and maybe ideas on how can I optimize this ? Thank you !
Gonna take on selbie's point here:
Every instance of if(umap.count(key)) will search for the key and using umap[key] is the equivalent for the search. You can avoid the double search by assigning an iterator which points to the key by a single std::unordered_map::find() operation.
selbie already gave the code for int get()'s search, here's the one for void put()'s one:
auto it = umap.find(key);
if (it != umap.end())
{
klist.erase(it ->second);
umap.erase(key);
}
Sidecase:
Not applicable for your code as of now due to lack of input and output work, but in case you use std::cin and std::cout, you can disable the synchronization between C and C++ streams, and untie cin from cout as an optimization: (they are tied together by default)
// If your using cin/cout or I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

Adding a new statement each iteration of a for loop. Queue with 2d arrray

I am trying to create a stream of numbers through a 2d array kind of like a queue but over 2 dimensions.
The final function will take std::string.
I have written some pretty horrific code.. eventually. I looked for a pattern but the thing that gets me is each time the number moves down the queue it needs another line of code and it has to move into the next element in the array.
I figure once I can do that I can put it in a loop.
so you basically add another line of code each time it adds a new number from the iterator.
intarray[0][0] = *it;
++it;
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][4] = intarray[0][3];
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][5] = intarray[0][4];
intarray[0][4] = intarray[0][3];
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][6] = intarray[0][5];
intarray[0][5] = intarray[0][4];
intarray[0][4] = intarray[0][3];
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
the numbers go down each time a new number is added from the iterator
I think these nested loops is what you need
auto jj = 1u;
while (!condition)
{
intarray[0][0] = *it;
++it;
for (auto ii=jj; ii >= 1 ; --ii)
intarray[0][ii] = intarray[0][ii-1];
++jj;
}
where condition is whatever condition when you need to stop the process.This code is not very efficient, though.
EDIT
As I understand you need to use both dimensions, so you have options:
a) if you know the size of your data beforehand, and I think it is the case, since you use statically allocated intarray[N][M]:
for (auto kk=N-1; 0 <= kk; --kk)
for (auto ii=M-1; 0 <= ii ; --ii)
{
intarray[kk][ii] = *it;
++it;
}
you simply fill the array in reverse order, and there is no need to overwrite values many times.
b) if you don't know the size beforehand, but have enough memory (and time):
populate dynamically-sized container (I'd recommend std::vector<int>) with data and go route a)
c) if you don't know the size beforehand and don't have enough memory to hold temporary container, you are not able to use statically allocated array. The only solution I see is to populate an std::vector<T> with data, and then write a wrapper function to get the elements in right order.
EDIT2:
According to the image you posted in the commentary, you need simple wrapper around an array. Disclaimer: I have not tested the code below, nevertheless, it should work, maybe after minor tweaks.
//while you can do it without class, I prefer this way
class MyArray
{
public:
//push value in the array
void push_back(const int a)
{
//move values using std::memmove as suggested above
std::memmove(&(arr[1]),&(arr[0]),2*N - 1);
//store first element
arr[0]=a;
}
//calculate index in array and return
int at(const int a, const int b)
{
if (0 == a) //first row
return arr.at(b); //return just the index
if (1 == a) //second row
return arr.at(N - 1 - b); //if
}
private:
//dimension of the array
static const int N = 10;
//contiguous static array is enough here
//one can use C-style array, but no point for doing so
std::array<int, 2*N> arr;
}
//usage
MyArray mArr;
while(!condition)
{
mArr.push_back(*it);
std::cout<<mArr.at(1,2)<<std::endl;
}
To 'move the queue' it is handy to use std::memmove, as suggested by Some programmer dude. Since std::memmove operates over contiguous memory, use std::array, std::vector or 1D C-style array instead of 2D C-style array to hold all elements. To get values calculate the right index for it, depending on the row (first or second).

How to get int position of vector loop

How to get int position of this loop? Thank you.
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (; a != vect.end() && b != vect2.end() && c != vect3.end(); a++, b++, c++) {
}
I need to print values of other variable, but I need to get actual unsigned int position of this vector loop.
I need to print double vector using this position of this vector.
And how to get the last index of vector.
My problem is for for loop with multiple vectors and getting index from it next to use only last of indexes.
As Angew shows, a simple indexed loop may be preferable when you need indices.
However, it is possible to get the index from an iterator as well:
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (/*the loop conditions*/) {
auto index = a - vect.begin();
}
It is also possible to get the index of a forward iterator using std::distance, but it would be unwise to use it in a loop, since the complexity will be linear for non-random-access iterators.
In the case of forward iterators (and generic code that must support forward iterators), you can write a loop which has both the index variable, and the iterators.
P.S. it is potentially preferable to use pre-increment with iterators. Probably only matters in debug build.
It's simple: if you need indices, don't use iterators:
for (
size_t idx = 0, idxEnd = std::min({vect.size(), vect2.size(), vect3.size()});
idx < idxEnd;
++idx
)
{
auto& obj1 = vect[idx];
auto& obj2 = vect2[idx];
auto& obj3 = vect3[idx];
}
(The above code initialises idxEnd once at the start of the loop, so that it's not needlessly recomputed at each iteration. It's just an optimisation).

object from vector with structs

i 'm pretty new to c++, can you help me with pointers ? i have a struct
struct Slice
{
Slice(): {}
SliceObj *slObj;
};
and vector:
std::vector<Slice> slices;
So on mouce touch i want to take this object to change his public var:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice slice0 = slices[0];
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
And of coure of course when in drag method i make : slObj->rect.x = x+0.1;, it doesn't make anything good.
Please, help me with this, i can't understand how to carefully get obj with * from another object from vector and then carefully change it's param;
Trouble is in "how to carefully get SliceObj from slice0", not address of var, but this instance.
So here i need to get slObj param, that in future i can make slObj.rect.x = 1;
UPDATE:
when i make slObj->drag method i always see only strange number like:
but then, when glutPostRedisplay called and it's redraw on method
void SliceObj::draw(SliceObj *slObj)
then it's all good!
You should access the element through the iterator:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice& slice0 = *it //Get the element using iterator (Note the reference, is to avoid copy)
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
However, if you have a C++11 capable compiler, you could simplify things using range-based for loop:
for( auto& slObj : slices )
{
liceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}
You need to use the iterator to get the element from the vector. Here you are always getting the first element. Try this:
for (vector<Slice>::iterator it = slices.begin(); it != slices.end(); ++it) {
Slice slice0 = *it //Get the element using iterator
SliceObj *slObj = slice0.slObj;
slObj->drag(slObj, x, y);
}

How to iterate through map, modify map but restore at each iteration?

I have a std::map<int,int> lets call it my_map
I iterate through this map using iterators and a for loop.
Within each iteration I want to modify many elements in this map but restore it again to its original values for next iteration of the loop.
I thought I could create a temporary copy of the iterator my_temp_map , but then I wouldn't be able to use the iterator to find the element I ought to be working on.
I then thought I could create a temporary copy, work on the origin my_map and at the end of each loop restore the original back to the temporary copy. However I believe this would invalidate the iterators as an assignment deletes all elements
How does one solve this problem?
Code added
So each inner loop will modify current_partition (and there is some more absent code that will store the result of the modified current_partition), but after each inner_loop I need current_loop to be restored to its former self.
std::map<int,int> current_partition = bitset_to_map(centre->second->bit_partitions);
int num_parts = (std::max_element(current_partition.begin(), current_partition.end(),value_comparer))->second;
for (std::map<int,int>::iterator itr = current_partition.begin(); itr != current_partition.end(); ++itr) {
for (int next_part = 0; next_part<num_parts+1; ++next_part) {
if (next_part != itr->second) {
int current_part = itr->second;
itr->second = next_part;
std::vector<int> first_changed_part, last_changed_part;
for (std::map<int,int>::iterator new_itr = current_partition.begin(); new_itr != current_partition.end(); ++new_itr) {
if (new_itr->second == current_part)
first_changed_part.push_back(new_itr->first);
if (new_itr->second == next_part)
last_changed_part.push_back(new_itr->first);
}
}
}
}
I think that std::advance may be of help. Create the temp, then advance begin() until you're where you are now (found out with std::distance)...then whatever it is you're trying to do.
With the code, I understand what you're going for now. I'd do it pretty much the first way you suggest: each time through the outer loop, make a temporary copy of the current_partition data structure, and then work on that, discarding it at the end.
You said that the problem with that would be that you couldn't use an iterator into the original map to find the element you ought to be working on. That's true; you can't do that directly. But it's a map. The element you're working on will have a key which will be the same in any copy of the data structure, so you can use that to create an iterator to the element that you ought to be working on in the copy.
For instance:
std::map<int,int> current_partition = bitset_to_map(centre->second->bit_partitions);
int num_parts = (std::max_element(current_partition.begin(), current_partition.end(),value_comparer))->second;
for (std::map<int,int>::iterator itr = current_partition.begin(); itr != current_partition.end(); ++itr) {
// Make a temporary copy of the map. Iterators between the original and the copy aren't
// interchangeable, but the keys are.
std::map<int,int> tmp_current_partition = current_partition;
// Use the iterator itr to get the key for the element you're working on (itr->first),
// and then use that key to get an equivalent iterator into the temporary map using find()
std::map<int,int>::iterator tmp_itr = tmp_current_partition.find(itr->first);
// Then just replace current_partition with tmp_current_partition and
// itr with tmp_itr in the remainder (hopefully I didn't miss any)
for (int next_part = 0; next_part<num_parts+1; ++next_part) {
if (next_part != tmp_itr->second) {
int current_part = tmp_itr->second;
tmp_itr->second = next_part;
std::vector<int> first_changed_part, last_changed_part;
for (std::map<int,int>::iterator new_itr = tmp_current_partition.begin(); new_itr != tmp_current_partition.end(); ++new_itr) {
if (new_itr->second == current_part)
first_changed_part.push_back(new_itr->first);
if (new_itr->second == next_part)
last_changed_part.push_back(new_itr->first);
}
}
}
}