I have created a set of pairs in C++ to hold potentially colliding pairs of particles for a simple particle simulation as follows:
std::set<std::pair<int, int>> uniquePairs;
Once populated I want to iterate through it ONLY for the live particles in the simulation to check the distances between them for interaction later. I can iterate through the complete set like so...
std::set<std::pair<int,int>>::iterator it;
for (it = uniquePairs.begin(); it != uniquePairs.end(); ++it)
{
std::cout << it->first << std::endl;
}
BUT, this will throw up a vector 'out of range' error since I would be trying to access particles that are not yet alive. Therefore I want to be able to access the list UP TO the same number of live particles .. i.e N = particles.size().
Please help,
Many thanks!
Not absolutely clear in the question, If the question is, 'How to iterate on first N elements of a container?', below is the way to do it.
void foo(std::set<std::pair<int,int>>& uniquePairs, int N) {
auto it = uniquePairs.begin();
for (int i = 0; i < N; ++i)
{
std::cout << it->first << std::endl;
++it;
assert(it != uniquePairs.end());
}
}
CC: https://gcc.godbolt.org/z/tSHQYP
Related
These two example both work and do the same thing.
I'm just trying to get what is the difference between them in terms of optimization, speed and overall. Which approach is better and why? Thanks in advance.
First example:
std::map<std::vector<int>, std::vector<double>> data
printMap(&data);
...
void printMap(std::map<std::vector<int>, std::vector<double>> *p_data){
for(std::map<std::vector<int>, std::vector<double>>::iterator itr = p_data->begin(); itr != p_data->end(); ++itr){
for(auto it = itr->first.begin(); it != itr->first.end(); ++it){
std::cout << *it << std::endl;
}
for(auto it2 = itr->second.begin(); it2 != itr->second.end(); ++it2){
std::cout << *it2 << std::endl;
}
}
}
Second example:
std::map<std::vector<int>, std::vector<double>> data;
printMapRef(data);
void printMapRef(std::map<std::vector<int>,std::vector<double>> &data){
for(std::map<std::vector<int>, std::vector<double>>::iterator itr = data.begin(); itr != data.end(); ++itr){
std::vector<int> tempVecInt = (*itr).first;
std::vector<double> tempVecDouble = (*itr).second;
for (int i = 0; i < tempVecInt.size(); i++){
std::cout << tempVecInt.at(i) << " ";
}
for (int j = 0; j < tempVecDouble.size(); j++){
std::cout << tempVecDouble.at(j) << " ";
}
}
}
The obvious difference is that the first iterates through the vectors that are in the map, while the second creates copies of the vectors in the map, then iterates through the copies.
The second also uses .at to index into each vector, which checks that the index is within bounds (and throws an exception if it isn't).
Especially if the vectors are large, those could easily make the second significantly slower than the first.
Most of the other differences are mostly syntactic. Personally I don't particularly like the syntax of the iterator-based loop, but iterators vs. indices is unlikely to make any real difference in speed or anything like that.
For what little it's worth, my own preference would be to pass the map in by (const) reference and use range-based for loops. I'd also at least consider using a function to print out the contents of each vector, since you have two loops that should be essentially identical.
I am trying to figure out the best way of accessing a position in a vector using an iterator. I'm aware iterators behave like pointers, so this is the only method I came up with. I would like to know if there's a better or just a different way. Here's the code:
//This is a pointer to a vector of the class Particle BTW. vector < Particle > *particleList;
vector<Particle>::iterator it = particleList->begin();
// I assign a specific position outside the loop to a new iterator that won't be affected
vector<Particle>::iterator it2 = particleList->begin() + 3;
for( it; it != particleList->end(); it++){
it->draw();
//I'm interested in the velocity of this element in particular
cout << it2->vel << endl;
}
Thanks,
M
Try the following
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
std::cout << (i+3)->vel << "\n";
}
Note, there is no reason to use std::endl, std::endl has an implicit flush which lowers performance when outputting to say a log file, and when outputting to console it is already line buffered meaning that a line ending will already flush.
Note 2, you can only use + with i since i is a random access iterator because particleList is a std::vector, if you change say particleList to a std::list then the iterator will be a bidirectional iterator instead of a random access iterator and you will not be able to use + in that case you would need to use std::advance like WhozCraig mentioned, but do so on a copy like so:
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
auto i2 = i;
std::advance(i2, 3)
std::cout << i2->vel << "\n";
}
Though personally, in this case I would just iterate with two iterators instead of std::advance since std::advance is linear in time. Do something like:
auto i = particleList->begin();
auto i2 = particleList->begin();
std::advance(i2, 3);
for (; i < particleList->end(); ++i, ++i2) {
i->draw();
std::cout << i2->vel << "\n";
}
Note 3: (i+3) and i2 will run off the end of your list (vector), so do something smart there.
Hey here is a trick question asked in class today, I was wondering if there is a way to find a unique number in a array, The usual method is to use two for loops and get the unique number which does not match with all the others I am using std::vectors for my array in C++ and was wondering if find could spot the unique number as I wouldn't know where the unique number is in the array.
Assuming that we know that the vector has at least three
elements (because otherwise, the question doesn't make sense),
just look for an element different from the first. If it
happens to be the second, of course, we have to check the third
to see whether it was the first or the second which is unique,
which means a little extra code, but roughly:
std::vector<int>::const_iterator
findUniqueEntry( std::vector<int>::const_iterator begin,
std::vector<int>::const_iterator end )
{
std::vector<int>::const_iterator result
= std::find_if(
next( begin ), end, []( int value) { return value != *begin );
if ( result == next( begin ) && *result == *next( result ) ) {
-- result;
}
return result;
}
(Not tested, but you get the idea.)
As others have said, sorting is one option. Then your unique value(s) will have a different value on either side.
Here's another option that solves it, using std::find, in O(n^2) time(one iteration of the vector, but each iteration iterates through the whole vector, minus one element.) - sorting not required.
vector<int> findUniques(vector<int> values)
{
vector<int> uniqueValues;
vector<int>::iterator begin = values.begin();
vector<int>::iterator end = values.end();
vector<int>::iterator current;
for(current = begin ; current != end ; current++)
{
int val = *current;
bool foundBefore = false;
bool foundAfter = false;
if (std::find(begin, current, val) != current)
{
foundBefore = true;
}
else if (std::find(current + 1, end, val) != end)
{
foundAfter = true;
}
if(!foundBefore && !foundAfter)
uniqueValues.push_back(val);
}
return uniqueValues;
}
Basically what is happening here, is that I am running ::find on the elements in the vector before my current element, and also running ::find on the elements after my current element. Since my current element already has the value stored in 'val'(ie, it's in the vector once already), if I find it before or after the current value, then it is not a unique value.
This should find all values in the vector that are not unique, regardless of how many unique values there are.
Here's some test code to run it and see:
void printUniques(vector<int> uniques)
{
vector<int>::iterator it;
for(it = uniques.begin() ; it < uniques.end() ; it++)
{
cout << "Unique value: " << *it << endl;
}
}
void WaitForKey()
{
system("pause");
}
int main()
{
vector<int> values;
for(int i = 0 ; i < 10 ; i++)
{
values.push_back(i);
}
/*for(int i = 2 ; i < 10 ; i++)
{
values.push_back(i);
}*/
printUniques(findUniques(values));
WaitForKey();
return -13;
}
As an added bonus:
Here's a version that uses a map, does not use std::find, and gets the job done in O(nlogn) time - n for the for loop, and log(n) for map::find(), which uses a red-black tree.
map<int,bool> mapValues(vector<int> values)
{
map<int, bool> uniques;
for(unsigned int i = 0 ; i < values.size() ; i++)
{
uniques[values[i]] = (uniques.find(values[i]) == uniques.end());
}
return uniques;
}
void printUniques(map<int, bool> uniques)
{
cout << endl;
map<int, bool>::iterator it;
for(it = uniques.begin() ; it != uniques.end() ; it++)
{
if(it->second)
cout << "Unique value: " << it->first << endl;
}
}
And an explanation. Iterate over all elements in the vector<int>. If the current member is not in the map, set its value to true. If it is in the map, set the value to false. Afterwards, all values that have the value true are unique, and all values with false have one or more duplicates.
If you have more than two values (one of which has to be unique), you can do it in O(n) in time and space by iterating a first time through the array and filling a map that has as a key the value, and value the number of occurences of the key.
Then you just have to iterate through the map in order to find a value of 1. That would be a unique number.
This example uses a map to count number occurences. Unique number will be seen only one time:
#include <iostream>
#include <map>
#include <vector>
int main ()
{
std::map<int,int> mymap;
std::map<int,int>::iterator mit;
std::vector<int> v;
std::vector<int> myunique;
v.push_back(10); v.push_back(10);
v.push_back(20); v.push_back(30);
v.push_back(40); v.push_back(30);
std::vector<int>::iterator vit;
// count occurence of all numbers
for(vit=v.begin();vit!=v.end();++vit)
{
int number = *vit;
mit = mymap.find(number);
if( mit == mymap.end() )
{
// there's no record in map for your number yet
mymap[number]=1; // we have seen it for the first time
} else {
mit->second++; // thiw one will not be unique
}
}
// find the unique ones
for(mit=mymap.begin();mit!=mymap.end();++mit)
{
if( mit->second == 1 ) // this was seen only one time
{
myunique.push_back(mit->first);
}
}
// print out unique numbers
for(vit=myunique.begin();vit!=myunique.end();++vit)
std::cout << *vit << std::endl;
return 0;
}
Unique numbers in this example are 20 and 40. There's no need for the list to be ordered for this algorithm.
Do you mean to find a number in a vector which appears only once? The nested loop if the easy solution. I don't think std::find or std::find_if is very useful here. Another option is to sort the vector so that you only need to find two consecutive numbers that are different. It seems overkill, but it is actually O(nlogn) instead of O(n^2) as the nested loop:
void findUnique(const std::vector<int>& v, std::vector<int> &unique)
{
if(v.size() <= 1)
{
unique = v;
return;
}
unique.clear();
vector<int> w = v;
std::sort(w.begin(), w.end());
if(w[0] != w[1]) unique.push_back(w[0]);
for(size_t i = 1; i < w.size(); ++i)
if(w[i-1] != w[i]) unique.push_back(w[i]);
// unique contains the numbers that are not repeated
}
Assuming you are given an array size>=3 which contains one instance of value A, and all other values are B, then you can do this with a single for loop.
int find_odd(int* array, int length) {
// In the first three elements, we are guaranteed to have 2 common ones.
int common=array[0];
if (array[1]!=common && array[2]!=common)
// The second and third elements are the common one, and the one we thought was not.
return common;
// Now search for the oddball.
for (int i=0; i<length; i++)
if (array[i]!=common) return array[i];
}
EDIT:
K what if more than 2 in an array of 5 are different? – super
Ah... that is a different problem. So you have an array of size n, which contains the common element c more than once, and all other elements exactly once. The goal is to find the set of non-common (i.e. unique) elements right?
Then you need to look at Sylvain's answer above. I think he was answering a different question, but it would work for this. At the end, you will have a hash map full of the counts of each value. Loop through the hash map, and every time you see a value of 1, you will know the key is a unique value in the input array.
I want to store a table in C++(gcc) whose size I dont know before hand it will be decided on realtime which kind of structure to use??
Make a vector of the structure you use for a record in the table:
vector<MyRecord> v;
You add records (objects of type MyRecord) using:
v.push_back(record);
If you mean arrays that for most purpose std::vector or std::deque is what you are looking for.
std::vector<ClassOrTypeYouNeedToStore> v;
v.push_back(1):
v.push_back(2):
v.push_back(3):
std::cout << "Length of vector " << v.size() << std::endl;
// Before C++11
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++) {
std::cout << "Next element is " << *it << std::endl;
}
// C++11+
for (auto it = v.begin(); it != v.end(); it++) {
std::cout << "Next element is " << *it << std::endl;
}
It depends what you need to store and what will vary. If the columns are fixed and of different types and you want to be able to insert and remove rows dynamically, you might want a std::vector<std::tuple<T,U,V>> (or instead of a tuple, you can use a struct of some sort).
If the columns are fixed but all the same type, give a std::vector<std::array<T,N>> a go.
If the number of rows and columns are fixed and of the same type then try std::array<std::array<T,N>,M>.
If the number of rows and columns are fixed but each column is of different types, std::array<std::tuple<T,U,V>,N> should suit you fine.
If you want the number of columns to also vary, then you'll want the inner type to be a std::vector of some sort.
Usually in that case I would use std::vector.
size_t rsz = 4;
size_t csz = 4;
std::vector<double> table(rsz*csz, 0.0);
for (size_t i = 0; i < rsz; i++) {
for (size_t j = 0; j < csz; j++) {
table[i*csz+j] = i * 10 + j;
}
}
I tend to prefer 1D vector and just doing the offset arithmetic myself. It keeps your helper functions from being over-specialized.
As suggested, you can use vector<vector<CellType>>, vector<RowType>, or, if by "size" you mean "the number of lines" you can use vector<array<RowSize, CellType>> (my favourite solution).
Arrays have the advantage of constant length (performance, memory footprint, memory alignment), and in this solution you get about the same flexibility as in a relational DB.
So, I'm trying to tally the elements of an array. By this I mean, I have a large array, and each element will have multiples of itself throughout the array. I am trying to figure out how many times each element occurs, however I keep running into the issue of there being duplicate tallies. Since "x" could exist at 12 different places in the array, when I loop through it and keep a running sum, I get the tally for "x" 12 different times. Does anyone know of a simpler/better way to keep a tally of an array with no duplicates?
My code is:
where count is the number of elements
for(i=0;i<count;i++)
{
for(x=0; x<count;x++)
{
if(array[i]==array[x])
{
tallyz++;
}
}
tally[i]=tallyz-1;
tallyz=0;
}
}
std::map<X, unsigned> tally;
for(i = 0; i < count; ++i)
++tally[array[i]];
Note that this is best if the redundancy in the array is fairly high. If most items are unique you're probably better just sorting the array as others have mentioned.
If you can sort the array, simply sort it. Then all you have left is a linear scan of the elements, checking if the element behind this one is the same as the current element (don't forget bounds checking).
As an alternative to sorting, you could use a map:
template<class T, size_t N>
void printSums(T (array&)[N]) {
map<T, size_t> m;
for(T*p = array; p < array+N; ++p) {
++m[*p];
}
for(map<T,size_t>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << ": " << it->second << "\n";
}
}
Warning: this is untested code.
first use a map just as John said,then traverse the tally array:
std::map<X, unsigned> data;
for(i = 0; i < count; i++)
data[array[i]]++;
for(i = 0; i < count; i++)
tally[i]=data[tally[i]]-1;