Use Object in vector in loop - c++

Currently, i have a loop iterating through a vector, and i'm trying to find the index of an object, while i'm in the loop, to delete it. How can i go about this?
Here's my code :
for (Object &a : objectDict)
{
a.setTime(theTime);
double tempMoveX = 0, tempMoveZ = 0, tempUX = 0,tempUZ = 0;
for (Object &b : objectDict)
{
if (a != b)
{
...
debug << fixed << setprecision(20) << "Collision" << endl;
a.appendMass(b.getMass());
objectDict.erase(find(objectDict.begin(), objectDict.end(), b));
...
Thats the important part. How can i erase object b from the vector?

One easy way is to simply build a separate vector containing the indexes of elements to erase later. Once you've finished going through the regular vector, loop in reverse order through the "to be removed" vector (in reverse because you don't want to invalidate the indexes as you go), and erase them.
Alternatively, as you iterate over the original vector, select the elements you want to keep, and copy them to another vector. At the very end, swap the two vectors (which is cheap). This will work better if you have relatively many elements to delete, on average.

Well, in case you need an index while iterating vector's elements, instead of:
for (Object &a : objectDict) { ...
do traditional:
for (size_t i = 0; i < objectDict.size(); ++i) { ...
and within the loop's body: instead of using reference a, you'll use objectDict[i], then when you will need to erase element, you can do:
objectDict.erase(vec.begin() + i);
i--;
i-- is used to move the index backwards by 1 so that when the next iteration increments it again, the element that follows right after the element that has been erased is not skipped.

Related

std vector size keep ground Although i insert in the same indexs

Something wired i see here with std vector
I have
variable that its value is dynamically changes but always under 20
dynamicSizeToInsert in the example.
why the vector size keeps growing ?
std::vector<int> v;
//sometimes its 5 sometimes it is 10 sometimes it is N < 20
int dynamicSizeToInsert = 5
int c = 0;
for(std::vector<int>::size_type i = 0; i != 100; i++) {
if(c == dynamicSizeToInsert )
{
c = 0;
}
v.insert(v.begin() + c, c);
c++;
printf("%d",v.size()) //THIS THINK KEEP growing although i only using vector indexes 0 to 4 allways
}
i want to keep my vector side 5 elements big
and that new value will run over other value in the same index .
std::vector::insert, as the name suggests, inserts elements at the specified position.
When c == dynamicSizeToInsert, c is set to 0. So now, v.size() == 5. Now this lines executes:
v.insert(v.begin() + c, c);
This will insert 0 at posistion v.begin() + 0, which is position 0 and it will offset every other element (it will not replace the element at position 0), and so the vector keeps growing.
Instead of using insert, use operator[]:
//So that 'v' is the right size
v.resize(dynamicSizeToInsert);
for(std::vector<int>::size_type i = 0; i != 100; i++) {
if(c == dynamicSizeToInsert )
{
c = 0;
}
v[i] = c; //Sets current index to 'c'
c++;
}
insert doesn't replace element, rather it inserts element at given location and shifts all the right elements to one position right. That's why your vector size is growing.
If you want to replace an existing index then you can use operator[]. However, keep in mind that the index must be between 0 - size() - 1 in order to use operator[].
std::vector::insert inserts a new member into the array at the index you specify, and moving the other elements forward or even reallocating the array once it reaches capacity(a relatively expensive operation)
The vector is extended by inserting new elements before the element at
the specified position, effectively increasing the container size by
the number of elements inserted.
This causes an automatic reallocation of the allocated storage space
if -and only if- the new vector size surpasses the current vector
capacity.
(http://www.cplusplus.com/reference/vector/vector/insert/)
As quoted above, the vector is extended with every insert operation.
to get the behaviour you want you need to use the [] operator like so:
v[i] = some_new_value;
this way a new element is never added, its only the value of the ith element that is changed.
const int dynamicSizeToInsert = 5;
std::vector<int> v(dynamicSizeToInsert);
int c = 0;
for(std::vector<int>::size_type i = 0; i !=100; i++)
{
v.at(i%dynamicSizeToInsert) = (dynamicSizeToInsert == c?c = 0,c ++: c ++);
printf("%d",v.size());
}

how to get pairs of elements efficiently in a linked list (Haxe)

I have a list of objects and I would like to return each possible unique pair of objects within this list. Is the following the most efficient way to do that in Haxe?
for (elem1 in my_list)
{
for (elem2 in my_list)
{
if (elem1 == elem2)
{
break;
}
trace(elem1, elem2);
}
}
I would rather avoid the equality check if possible. The reason that I am not using arrays or vectors is that these lists will be added to/removed from very frequently and I have no need for index level access.
If you want to efficient (the less amount of iterations), you could loop like this:
for (i in 0 ... my_list.length-1) // loop to total minus 1
for (j in i+1 ... my_list.length) // start 1 further than i, loop to end
if (my_list[i] != my_list[j]) // not match
[my_list[i], my_list[j]]]; // make pair
Btw, it depends on the content if linked list or array actually faster, since this uses indexes now. You should test/measure it your case (don't assume anything if it's performance critic piece of code).
try online:
http://try.haxe.org/#2Ab3F

Find && Delete Duplicate vector elements in a for loop

I have these files in a vector
vector<string> myFileNames ={"TestFile1","TestFile2","copiedFile1","copiedFile2","copiedFile3"};
Should only have unique file left in list i.e. test file 1&2
vector<string> duplicateFilesFound;
To be filled with files that duplicates i.e. copiedFile 1, 2 && 3 are duplicates
vector<string> myMd5Strings;
Filled with md5 hash values
string target = " ";
int count = 0;
for (unsigned int i = 0; i < myFileNames.size(); ++i)
{
target = myMd5Strings[i];
for (unsigned int k = 1; k < myFileNames.size(); ++k)
{
if (target == myMd5Strings[k])
{
myFileNames.erase(myFileNames.begin() + k);
duplicateFilesFound.push_back(myFileNames[k]);
}
}
cout << "Duplicate Count is : " << duplicateFilesFound.size() << endl;
}
One mistake (maybe there are others) is that you are first getting the MD5 to test, but then your inner k loop will erroneously erase the first item matching the hash. For example, if your target (the i value) is at element 2, your loop doesn't check if k == 2 so as to skip over this first occurrence.
The test should be:
if ( i != k && target == myMd5Strings[k])
The second issue is that if you erase an item, you need to keep the k value where it is and not increment. Otherwise you will skip over the next item to check and miss this item if it matches the hash.
But even with pointing these gotchas out, your attempt is an order of n^2 -- you have 100 names, that is 10,000 iterations, 1,000 names, 1,000,000 iterations, etc. At the end of the day, this will perform poorly on large lists.
The approach mentioned below is logarithmic (due to the sort) in time, not quadratic, thus executing much faster for large list sizes.
But a few structural changes could be done. A better approach would be to store the file name, along with MD5 hash in a single struct. Then declare a container of this struct.
struct file_info
{
std::string filename;
std::string md5hash;
};
//...
std::vector<file_info> fInfoV;
Once you have this, then everything becomes very simple using some basic algorithm functions.
To remove duplicates with a certain md5 hash can be done by first sorting the list using the hash value as the sort criteria, and then removing the duplicates using std::unique and then erase.
#include <algorithm>
//...
std::sort(fInfoV.begin(), fInfoV.end(),
[](const file_info&f1, const file_info& f2)
{ f1.md5hash < f2.md5hash; });
// uniqueify the vector
auto iter = std::unique(fInfoV.begin(), fInfoV.end(),
[](const file_info& f1, const file_info& f2)
{ f1.md5hash == f2.md5hash; });
// for kicks, get the number of duplicates found
auto duplicateCount = std::distance(iter, fInfoV.end());
cout << "There are " << duplicateCount << " duplicates found";
// erase these duplicates
fInfoV.erase(iter, fInfoV.end());
The code above, sorts, uniquifies, and erases the duplicates. I threw in std::distance to show you that you can get the number of duplicates without having to create another vector. The code above also overcomes the need to write loops checking for equivalent loop indices, making sure you reseat the inner index, checking for bounds, etc.
As to time complexity:
The std::sort function is guaranteed to have logarithmic complexity.
The std::unique function has linear complexity:
So this will perform much better for large lists.

How to randomly assign to vector in C++?

I am new to C++, and am continuously told to use std::vector instead of new[].
I am trying to achieve this functionality, in where I know the size of the vector and want to assign to it randomly (not sequentially).
However, when running this, my program terminates with no error output, so I am stumped.
vector<string> v1;
v1.resize(2);
v1.insert(v1.begin() + 1, "world");
v1.insert(v1.begin() + 0, "world");
cout << v1.at(1) << endl;
Don't give up, it's easier than that
vector<string> v1(2);
v1[1] = "world";
v1[0] = "world";
cout << v1[1] << endl;
vector::insert is for when you want to add items to your vector, Not when you want to replace ones that are already there, vector::insert changes the size of the vector in other words.
First you resize it to have two empty strings:
{"", ""}
Then you insert "world" before begin() + 1 or the 2nd element:
{"", "world", ""}
Then you insert "world" before begin() or the 1st element:
{"world", "", "world, ""}
Then you access the 2nd element with v1.at(1) and get the empty string.
Presumably, you don't want std::vector::insert which inserts new elements between existing elements. You want to do this as you would with arrays, with operator[]:
vector<string> v1(2);
v1[1] = "world";
v1[0] = "world";
cout << v1.at(1) << endl;
To randomly assign
Simply use the index (obviously, validate that it's < size)
v1[index] = value;
To randomly insert (validate that index < size)
v1.insert(v1.begin() + index, value);
To sequentially insert at the end / append (no need for an index, your value will be inserted at the end of the vector)
v1.push_back(value);
If you plan on inserting many values, consider calling reserve() on your vector so that enough memory can be allocated to store all of your items, otherwise as you insert your data you may end up with many reallocation as the vector grows
Your Program is working correctly. Your error is in the logic of your code.
Insert doesn't change the string stored at index 1. It places a string at position 1, and moves all indexes after 1 to the right.
start first insert second insert
("","") -> ("", "world, "") -> ("world","","world","")
So when you print v1.at(1) you are printing an empty string.
To fix the issue, you would want to use:
v1.at(1)="world"
v1.at(0)="world"
--or--
v1[1] ="world"
v1[0] ="world"
The two solutions are equivalent, however the second will not do any bounds checking. The first will throw an error if there is an out of bounds error. This shouldn't matter as long as you can gaurantee that you will never index out of bounds.
Like many have stated, you can can just use operator[] to reassign old values, given that you've already sized the vector or filled it with other values.
If your array will always have a fixed size you can use std::array, which should provide a performance boost, at the sacrifice of the ability to resize the array or determine its size at runtime.
std::array<std::string,2> a1;
a1[0] = "world";
a1[1] = "world2";
std::cout<<a1.at(1)<<std::endl; //outputs world2
Note that the size must be static, so you can't do something like this:
int numStrings;
std::cin>>numStrings;
std::array<std::string,numStrings> a2; //ERROR
Unfortunately, I don't think there is any way of initializing an std::array without a default constructor, other than using an initialization list.
struct T
{
T(std::string s):str(s){} //no default constructor
std::string str;
}
std::array<T,2> a3 = {T(""), ""}; //you can use a conversion constructor implicitly
Obviously, this isn't practical if you want an array with a sizable number of objects.

vector constructor creating vector with one less element

I am trying to split a vector into "almost equal" parts, and create subvectors for those parts.
I have asked the original question here: How to split a vector into n "almost equal" parts but I found a really good solution, what I am trying to use, from here: Best way to extract a subvector from a vector?
I wrote this function for creating integers for start and end values (round is my function which rounds to specified digits.)
void split( double number, double parts )
{
double loop = number / parts;
for( int i = 0; i < parts; i++ )
{
int start = round( i * loop, 0 );
int end = round( ( i + 1 ) * loop - 1, 0 );
cout << start << " " << end << endl;
}
}
This function so far works OK, but my problem is that when I try to run this:
vector<some> dest( &source[start], &source[end] );
Then it creates one LESS element, then required. I mean for example if I call it with
vector<some> dest( &source[0], &source[99] );
then it will have 99 elements, instead of 100. Why is this happening?
How can I fix it? If I use [end+1], then it terminates at the last vector, with "subscript out of range."
The vector constructor (and all STL constructors that accept pointer ranges, for that matter) are designed to take in a range of STL-style iterators. When using iterators, you specify a range by providing a pointer to the first- and the past-the-end elements, not the first and last elements. If you wanted to create a vector as a copy of the subrange (0, 99) out of another vector, you could write
vector<some> dest(source.begin(), source.begin() + 100);
Note that this uses vector iterators to specify the slice of the first 100 elements rather than operator[], which has undefined behavior when the provided index is out of bounds. In your case, this undefined behavior is manifesting as a runtime debug error. Iterators don't have this problem, since they're specifically designed to be used this way.
If you want to use raw C++ arrays as input to the vector constructor, you could do it like this:
vector<some> dest(source, source + 100);
Hope this helps!
While it's not legal to use &v[n] if v is an std::vector with n elements you can use instead
vector<some> dest(v.begin()+first, v.begin()+last+1);
even if last+1 == n.