STL, reducing an array, c++ - c++

For a hw assignment, we are to code a reduce routine that looks like:
int reduce(long array[], int size)
//Where array is the array to reduce, and size is the size of the array.
Using STL. My initial thoughts were to create a set, put all items in the set with a comparison, but then I realized that the set I would create would never be usable since the function returns the size of the new set, but not the set itself to be used. So I'm not sure how I'd go about using the STL to reduce an array. Any thoughts? Thanks.
Edited:
Sorry, reduce is just to reduce the array into a sorted array without duplicates.
E.g. {4, 4, 2, 1} -> {1, 2, 4}

Sort the array using std::sort, then apply std::unique on it to remove duplicates. std::unique works only on sorted arrays. Just to simplify matters here is how you get begin and end of a native array:
long* begin = array;
long* end = array + size;
Once you have these two things, you can apply standard algorithms easily. Also, if you need to return the new size(used elements in the array):
long* end_after_unique = unique(...);
return end_after_unique - array;

std::map only allow a single entry and will sort the items for you automatically. The "second" value in your case is a don't care.
std::map<INT32,INT32> mymap;
mymap[i] = array[i];//inserts if not already present

Related

How do you delete an element from an array in C++? [duplicate]

How do I remove an element of an array and shift the remaining elements down. So, if I have an array,
array[]={1,2,3,4,5}
and want to delete 3 and shift the rest so I have,
array[]={1,2,4,5}
How would I go about this in the least amount of code?
You just need to overwrite what you're deleting with the next value in the array, propagate that change, and then keep in mind where the new end is:
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// delete 3 (index 2)
for (int i = 2; i < 8; ++i)
array[i] = array[i + 1]; // copy next element left
Now your array is {1, 2, 4, 5, 6, 7, 8, 9, 9}. You cannot delete the extra 9 since this is a statically-sized array, you just have to ignore it. This can be done with std::copy:
std::copy(array + 3, // copy everything starting here
array + 9, // and ending here, not including it,
array + 2) // to this destination
In C++11, use can use std::move (the algorithm overload, not the utility overload) instead.
More generally, use std::remove to remove elements matching a value:
// remove *all* 3's, return new ending (remaining elements unspecified)
auto arrayEnd = std::remove(std::begin(array), std::end(array), 3);
Even more generally, there is std::remove_if.
Note that the use of std::vector<int> may be more appropriate here, as its a "true" dynamically-allocated resizing array. (In the sense that asking for its size() reflects removed elements.)
You can use memmove(), but you have to keep track of the array size yourself:
size_t array_size = 5;
int array[5] = {1, 2, 3, 4, 5};
// delete element at index 2
memmove(array + 2, array + 3, (array_size - 2 - 1) * sizeof(int));
array_size--;
In C++, though, it would be better to use a std::vector:
std::vector<int> array;
// initialize array...
// delete element at index 2
array.erase(array.begin() + 2);
std::copy does the job as far as moving elements is concerned:
#include <algorithm>
std::copy(array+3, array+5, array+2);
Note that the precondition for copy is that the destination must not be in the source range. It's permissible for the ranges to overlap.
Also, because of the way arrays work in C++, this doesn't "shorten" the array. It just shifts elements around within it. There is no way to change the size of an array, but if you're using a separate integer to track its "size" meaning the size of the part you care about, then you can of course decrement that.
So, the array you'll end up with will be as if it were initialized with:
int array[] = {1,2,4,5,5};
You can't achieve what you want with arrays. Use vectors instead, and read about the std::remove algorithm. Something like:
std::remove(array, array+5, 3)
will work on your array, but it will not shorten it (why -- because it's impossible). With vectors, it'd be something like
v.erase(std::remove(v.begin(), v.end(), 3), v.end())
Depending on your requirements, you may want to use stl lists for these types of operations. You can iterate through your list until you find the element, and erase the element. If you can't use lists, then you'll have to shift everything yourself, either by some sort of stl algorithm or manually.
If you are most concerned about code size and/or performance (also for WCET analysis, if you need one), I think this is probably going to be one of the more transparent solutions (for finding and removing elements):
unsigned int l=0, removed=0;
for( unsigned int i=0; i<count; i++ ) {
if( array[i] != to_remove )
array[l++] = array[i];
else
removed++;
}
count -= removed;
Just so it be noted: If the requirement to preserve the elements order is relaxed it is much more efficient to replace the element being removed with the last element.
Programming Hub randomly provided a code snippet which in fact does reduce the length of an array
for (i = position_to_remove; i < length_of_array; ++i) {
inputarray[i] = inputarray[i + 1];
}
Not sure if it's behaviour that was added only later. It does the trick though.
It reduces length indeed. However, if we speak about int arrays, there is a difference between length and size.
Size tells us about a capacity of a given array, how much we can store in it.
Length of an array tells us about how many items are there actually.
This question is bit old.
Try using standard library provided containers. These are designed by experts and very well tested. Moreover future developments of standard library algorithms are designed to suite these standard library containers.
If for some reason you have to stick to array, then try using std::array
std::array<int, 5> array = { 1,2,3,4,5 };
//std::remove - The elements that are not deleted are moved to the front of the array,
//and returns the iterator of the element from where it can be completely erased.
auto itr = std::remove(array.begin(), array.end(), 3);
//New array with new size
std::array<int,4> newArray;
std::copy(array.begin(), itr, newArray.begin());
The same thing can be done without using std::array also. But as said earlier for many other benifits prefer to go with std::array
int array[] = { 1,2,3,4,5 };
auto itr = std::remove(std::begin(array), std::end(array), 3);
int newArray[4];
std::copy(std::begin(array), itr, std::begin(newArray));

Get 5 last array objects C++

A simple task, but I don't remember the syntax for C++.
int array[n];
I need to get the last 5 objects of the array.
array.slice(array.length - 5, 1)??
In short
Algorithms will be your friends:
int last[5];
std::copy(array+n-5, array+n, last);
More details
First, the variable length array is not standard C++. So the following code is only portable and valid if n is a constant expression:
int array[n];
So the better approach would be to use vectors of int. The advantage is that their size may evolve dynamically when needed:
vector<int> varray(n);
If really you want to use variable raw arrays, you could use memory allocation, but this is cumbersome since you have to take a lot of precautions (e.g. deleting the allocated object in the end):
int *array = new int[n];
The solution with raw arrays is displayed above. I leave it up to you to generalize it to the k last elements.
The vector variant is very similar:
vector<int> vlast(5);
copy(varray.end()-vlast.size(), varray.end(), vlast.begin());
Note that the copy is more dynamic, since the number of elements will depend on the size of the output vector.
Attention - risk of UB: I leave you as an exercise to adapt the code for both solutions to the case where the size of the array would be smaller than 5.
Now if you like algorithms, it's worth also to look at iterators, because they allow you to do cool tricks like:
copy(vlast.begin(), vlast.end(), ostream_iterator<int>(cout," ")); // display
cout<<endl;
Online demo
Still not convinced by vectors ? Then have a look at these two other vector variants:
vector<int> vlast2(varray.end()-5, varray.end()); // powerful constructor
vector<int> vlast3(varray.rbegin(), varray.rbegin()+5); // and in reverse order

To delete multiple elements in array c++ with the shift [duplicate]

How do I remove an element of an array and shift the remaining elements down. So, if I have an array,
array[]={1,2,3,4,5}
and want to delete 3 and shift the rest so I have,
array[]={1,2,4,5}
How would I go about this in the least amount of code?
You just need to overwrite what you're deleting with the next value in the array, propagate that change, and then keep in mind where the new end is:
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// delete 3 (index 2)
for (int i = 2; i < 8; ++i)
array[i] = array[i + 1]; // copy next element left
Now your array is {1, 2, 4, 5, 6, 7, 8, 9, 9}. You cannot delete the extra 9 since this is a statically-sized array, you just have to ignore it. This can be done with std::copy:
std::copy(array + 3, // copy everything starting here
array + 9, // and ending here, not including it,
array + 2) // to this destination
In C++11, use can use std::move (the algorithm overload, not the utility overload) instead.
More generally, use std::remove to remove elements matching a value:
// remove *all* 3's, return new ending (remaining elements unspecified)
auto arrayEnd = std::remove(std::begin(array), std::end(array), 3);
Even more generally, there is std::remove_if.
Note that the use of std::vector<int> may be more appropriate here, as its a "true" dynamically-allocated resizing array. (In the sense that asking for its size() reflects removed elements.)
You can use memmove(), but you have to keep track of the array size yourself:
size_t array_size = 5;
int array[5] = {1, 2, 3, 4, 5};
// delete element at index 2
memmove(array + 2, array + 3, (array_size - 2 - 1) * sizeof(int));
array_size--;
In C++, though, it would be better to use a std::vector:
std::vector<int> array;
// initialize array...
// delete element at index 2
array.erase(array.begin() + 2);
std::copy does the job as far as moving elements is concerned:
#include <algorithm>
std::copy(array+3, array+5, array+2);
Note that the precondition for copy is that the destination must not be in the source range. It's permissible for the ranges to overlap.
Also, because of the way arrays work in C++, this doesn't "shorten" the array. It just shifts elements around within it. There is no way to change the size of an array, but if you're using a separate integer to track its "size" meaning the size of the part you care about, then you can of course decrement that.
So, the array you'll end up with will be as if it were initialized with:
int array[] = {1,2,4,5,5};
You can't achieve what you want with arrays. Use vectors instead, and read about the std::remove algorithm. Something like:
std::remove(array, array+5, 3)
will work on your array, but it will not shorten it (why -- because it's impossible). With vectors, it'd be something like
v.erase(std::remove(v.begin(), v.end(), 3), v.end())
Depending on your requirements, you may want to use stl lists for these types of operations. You can iterate through your list until you find the element, and erase the element. If you can't use lists, then you'll have to shift everything yourself, either by some sort of stl algorithm or manually.
If you are most concerned about code size and/or performance (also for WCET analysis, if you need one), I think this is probably going to be one of the more transparent solutions (for finding and removing elements):
unsigned int l=0, removed=0;
for( unsigned int i=0; i<count; i++ ) {
if( array[i] != to_remove )
array[l++] = array[i];
else
removed++;
}
count -= removed;
Just so it be noted: If the requirement to preserve the elements order is relaxed it is much more efficient to replace the element being removed with the last element.
Programming Hub randomly provided a code snippet which in fact does reduce the length of an array
for (i = position_to_remove; i < length_of_array; ++i) {
inputarray[i] = inputarray[i + 1];
}
Not sure if it's behaviour that was added only later. It does the trick though.
It reduces length indeed. However, if we speak about int arrays, there is a difference between length and size.
Size tells us about a capacity of a given array, how much we can store in it.
Length of an array tells us about how many items are there actually.
This question is bit old.
Try using standard library provided containers. These are designed by experts and very well tested. Moreover future developments of standard library algorithms are designed to suite these standard library containers.
If for some reason you have to stick to array, then try using std::array
std::array<int, 5> array = { 1,2,3,4,5 };
//std::remove - The elements that are not deleted are moved to the front of the array,
//and returns the iterator of the element from where it can be completely erased.
auto itr = std::remove(array.begin(), array.end(), 3);
//New array with new size
std::array<int,4> newArray;
std::copy(array.begin(), itr, newArray.begin());
The same thing can be done without using std::array also. But as said earlier for many other benifits prefer to go with std::array
int array[] = { 1,2,3,4,5 };
auto itr = std::remove(std::begin(array), std::end(array), 3);
int newArray[4];
std::copy(std::begin(array), itr, std::begin(newArray));

getting the number of elements in a struct

I have a struct:
struct KeyPair
{
int nNum;
string str;
};
Let's say I initialize my struct:
KeyPair keys[] = {{0, "tester"},
{2, "yadah"},
{0, "tester"}
};
I would be creating several instantiations of the struct with different sizes. So for me to be able to use it in a loop and read it's contents, I have to get the number of elements in a struct. How do I get the number of elements in the struct? In this example I should be getting 3 since I initialized 3 pairs.
If you're trying to calculate the number of elements of the keys array you can simply do sizeof(keys)/sizeof(keys[0]).
The point is that the result of sizeof(keys) is the size in bytes of the keys array in memory. This is not the same as the number of elements of the array, unless the elements are 1 byte long. To get the number of elements you need to divide the number of bytes by the size of the element type which is sizeof(keys[0]), which will return the size of the datatype of key[0].
The important difference here is to understand that sizeof() behaves differently with arrays and datatypes. You can combine the both to achieve what you need.
http://en.wikipedia.org/wiki/Sizeof#Using_sizeof_with_arrays
sizeof(keys)/sizeof(*keys);
If you're trying to count the elements of the array, you can make a macro
#define NUM_OF(x) (sizeof(x)/sizeof(x[0]))
You mean the count of elements in keys ? In such a case you can use int n = sizeof(keys)/sizeof(keys[0]);
In C++ it is generally not possible to do this. I suggest using std::vector.
The other solutions work in your specific case, but must be done at compile time. Arrays you new or malloc will not be able to use those tricks.
If you're trying to calculate the number of elements of the keys array
you can simply do sizeof(keys)/sizeof(keys[0]).
This can not be a general good solution, due to structure padding.

How do you copy the contents of an array to a std::vector in C++ without looping?

I have an array of values that is passed to my function from a different part of the program that I need to store for later processing. Since I don't know how many times my function will be called before it is time to process the data, I need a dynamic storage structure, so I chose a std::vector. I don't want to have to do the standard loop to push_back all the values individually, it would be nice if I could just copy it all using something similar to memcpy.
There have been many answers here and just about all of them will get the job done.
However there is some misleading advice!
Here are the options:
vector<int> dataVec;
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
// Method 1: Copy the array to the vector using back_inserter.
{
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
dataVec.reserve(dataVec.size() + dataArraySize);
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 3: Memcpy
{
dataVec.resize(dataVec.size() + dataArraySize);
memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}
// Method 4: vector::insert
{
dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}
// Method 5: vector + vector
{
vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}
To cut a long story short Method 4, using vector::insert, is the best for bsruth's scenario.
Here are some gory details:
Method 1 is probably the easiest to understand. Just copy each element from the array and push it into the back of the vector. Alas, it's slow. Because there's a loop (implied with the copy function), each element must be treated individually; no performance improvements can be made based on the fact that we know the array and vectors are contiguous blocks.
Method 2 is a suggested performance improvement to Method 1; just pre-reserve the size of the array before adding it. For large arrays this might help. However the best advice here is never to use reserve unless profiling suggests you may be able to get an improvement (or you need to ensure your iterators are not going to be invalidated). Bjarne agrees. Incidentally, I found that this method performed the slowest most of the time though I'm struggling to comprehensively explain why it was regularly significantly slower than method 1...
Method 3 is the old school solution - throw some C at the problem! Works fine and fast for POD types. In this case resize is required to be called since memcpy works outside the bounds of vector and there is no way to tell a vector that its size has changed. Apart from being an ugly solution (byte copying!) remember that this can only be used for POD types. I would never use this solution.
Method 4 is the best way to go. It's meaning is clear, it's (usually) the fastest and it works for any objects. There is no downside to using this method for this application.
Method 5 is a tweak on Method 4 - copy the array into a vector and then append it. Good option - generally fast-ish and clear.
Finally, you are aware that you can use vectors in place of arrays, right? Even when a function expects c-style arrays you can use vectors:
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
If you can construct the vector after you've gotten the array and array size, you can just say:
std::vector<ValueType> vec(a, a + n);
...assuming a is your array and n is the number of elements it contains. Otherwise, std::copy() w/resize() will do the trick.
I'd stay away from memcpy() unless you can be sure that the values are plain-old data (POD) types.
Also, worth noting that none of these really avoids the for loop--it's just a question of whether you have to see it in your code or not. O(n) runtime performance is unavoidable for copying the values.
Finally, note that C-style arrays are perfectly valid containers for most STL algorithms--the raw pointer is equivalent to begin(), and (ptr + n) is equivalent to end().
If all you are doing is replacing the existing data, then you can do this
std::vector<int> data; // evil global :)
void CopyData(int *newData, size_t count)
{
data.assign(newData, newData + count);
}
std::copy is what you're looking for.
Since I can only edit my own answer, I'm going to make a composite answer from the other answers to my question. Thanks to all of you who answered.
Using std::copy, this still iterates in the background, but you don't have to type out the code.
int foo(int* data, int size)
{
static std::vector<int> my_data; //normally a class variable
std::copy(data, data + size, std::back_inserter(my_data));
return 0;
}
Using regular memcpy. This is probably best used for basic data types (i.e. int) but not for more complex arrays of structs or classes.
vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
std::vector<int> myvector (dataArraySize );//target
std::copy ( myints, myints+dataArraySize , myvector.begin() );
//myvector now has 1,2,3,...10 :-)
Yet another answer, since the person said "I don't know how many times my function will be called", you could use the vector insert method like so to append arrays of values to the end of the vector:
vector<int> x;
void AddValues(int* values, size_t size)
{
x.insert(x.end(), values, values+size);
}
I like this way because the implementation of the vector should be able to optimize for the best way to insert the values based on the iterator type and the type itself. You are somewhat replying on the implementation of stl.
If you need to guarantee the fastest speed and you know your type is a POD type then I would recommend the resize method in Thomas's answer:
vector<int> x;
void AddValues(int* values, size_t size)
{
size_t old_size(x.size());
x.resize(old_size + size, 0);
memcpy(&x[old_size], values, size * sizeof(int));
}
avoid the memcpy, I say. No reason to mess with pointer operations unless you really have to. Also, it will only work for POD types (like int) but would fail if you're dealing with types that require construction.
In addition to the methods presented above, you need to make sure you use either std::Vector.reserve(), std::Vector.resize(), or construct the vector to size, to make sure your vector has enough elements in it to hold your data. if not, you will corrupt memory. This is true of either std::copy() or memcpy().
This is the reason to use vector.push_back(), you can't write past the end of the vector.
Assuming you know how big the item in the vector are:
std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));
http://www.cppreference.com/wiki/stl/vector/start