Related
int array[3][3][8] = {
{{3, 4, 5}, {3, 5, 7}, {5, 6, 7}},
{{1, 3, 5}, {0, 1, 2, 3, 4, 5, 6, 7}, {1, 5, 7}},
{{1, 2, 3}, {1, 3, 7}, {0, 1, 7}}
};
User inputs x,y coordinate and direction, at that location they can only move in 0-7 direction. However, each location can only move towards certain direction. Therefore I am making this array to see if that direction is in that x, y coordinate’s array. After I get the 3rd dimension array (becomes 1d array), I will see if user input direction is in that array.
For example:
{3,4,5} at 1x1 // then check if direction is in this array
I tried:
int new_array[8] = array[1][1];
Error: array must be initialized with a brace-enclosed initializer
int new_array = array[1][1][]; // {3,4,5}
Error: expected primary-expression before ']' token
So I know this syntax isn't valid, are there other ways to achieve such operation?
To copy the 3rd dimension array into a new array.
You could use std::copy:
#include <algorithm>
#include <iterator>
//...
int new_array[8];
std::copy(std::begin(array[1][1]),
std::end(array[1][1]),
new_array);
Done using std::array:
#include <array>
// ...
std::array<std::array<std::array<int, 8>, 3>, 3> array = {{
{{
{3,4,5},
{3,5,7},
{5,6,7}
}},
{{
{1,3,5},
{0,1,2,3,4,5,6,7},
{1,5,7}
}},
{{
{1,2,3},
{1,3,7},
{0,1,7}
}},
}};
std::array<int, 8> new_array = array[1][1];
// the same result but simpler:
auto new_array = array[1][1];
there is no way you can get the col or row of an array like that...
if you define a primitive array then you have to navigate the cells and asign the values
int main() {
int test[2][3][2] = {
{
{1, 2},
{3, 4},
{5, 6}
},
{
{7, 8},
{9, 10},
{11, 12}
}
};
int z[2];
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 2; ++k) {
z[k] = test[i][j][k];
}
}
}
for (int k = 0; k < 2; ++k)
{
cout << "z[" << k << "] = " << z[k] << endl;
}
return 0;
Assume I have two non-constant iterators begin and end. I want to completely replace the range between begin and end with values, that are between two other iterators. I know with non-constant iterators I can use the following syntax.
*begin = *result.begin();
*end = *result.end();
But this will only change the values behind begin and end iterators
To be more precise.
I have an initial vector
{1, 2, 3, 4, 5, 6, 7}
^ ^
begin end
and some other vector called result, which contains
{6, 6, 3, 5, 4, 13, 99}
^ ^
begin end
at the end I want my initial array to look like
{6, 3, 5, 4, 5, 6, 7}
Using std::copy(), it can be done like this:
#include <iostream>
#include <vector>
#include <algorithm>
void printVector(const std::vector<int>& v) {
bool first = true;
std::cout << '{';
for (int i : v) {
if (!first) std::cout << ", ";
std::cout << i;
first = false;
}
std::cout << "}\n";
}
int main(void) {
std::vector<int> v1 = {1, 2, 3, 4, 5, 6, 7};
std::vector<int> v2 = {6, 6, 3, 5, 4, 13, 99};
printVector(v1);
printVector(v2);
std::vector<int>::iterator dest_begin = v1.begin();
std::vector<int>::iterator src_begin = std::next(v2.begin(), 1);
std::vector<int>::iterator src_end = std::next(v2.begin(), 5);
std::copy(src_begin, src_end, dest_begin);
printVector(v1);
return 0;
}
Output:
{1, 2, 3, 4, 5, 6, 7}
{6, 6, 3, 5, 4, 13, 99}
{6, 3, 5, 4, 5, 6, 7}
Use std::copy:
std::copy(begin2, end2, begin1);
It copies the range between begin and end into another range, which starts at begin. Note that all these iterators are different, so I called them 1 and 2.
Is this is the right way to store and print?
int array[5];
int a1[3][3], a2[3][3], a3[3][3], a4[3][3], a5[3][3];
int array[0] = a1[3][3];
int array[1] = a2[3][3];
int array[2] = a3[3][3];
int array[3] = a4[3][3];
int array[4] = a5[3][3];
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
a1[i][j] = 0;
}
}
Similarly, filling the rest arrays.
Now Printing,
for(int i=0;i<5;i++) {
cout<<array[i];
}
did n't get the expected output.
How to print the a1,a2,a3,a4 and a5 from array?
So instead of using old plain c-arrays, use the in-build C++ std::array, if you want fixed-sized arrays. If the range should be dynamic you can switch std::array with std::vector. Look up the different definitions:
#include <array>
#include <iostream>
// a 2D-array is nothing else, than an array containing anotehr array
// what we do, is to define an array with size 3 containing an array with size 3
// this equals int a[3][3];
// this we do 5 times as requested
std::array<std::array<int, 3>, 3> a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::array<std::array<int, 3>, 3> a2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::array<std::array<int, 3>, 3> a3 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::array<std::array<int, 3>, 3> a4 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
std::array<std::array<int, 3>, 3> a5 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// now for the array which should contain the other arrays:
// we define a size of 5
// and it should contain the array which contains the array both of size 3
std::array<std::array<std::array<int, 3>, 3>, 5> the_array;
int main() {
// we directly assign the array specifier to the value
// which should contain the specified array
the_array[0] = a1;
the_array[1] = a2;
the_array[2] = a3;
the_array[3] = a4;
the_array[4] = a5;
// now we cannot print the arrays at once,
// we have to iterate "down" to the int to print it
for(auto sub_array2D : the_array) { // iterate over the array containing the 5 arrays
for(auto sub_array1D : sub_array2D) { // now iterate over one array in the array of the 2d array
for(auto elem : sub_array1D) { // at last, access the int element and print it out
std::cout << elem << " ";
}
std::cout << "\t"; // formatting
}
std::cout << "\n"; // formatting
}
return 0;
}
I have following vectors:
std::vector<A*> vec;
std::vector<std::pair<A*, A*>> vec_pair;
vec_pair size is much more than vec size. I would like to find a pair within vec_pair which both members are inside vec.
contents of the vec_pair are constant. However after each iteration the contents of the vec will change and I would like to do the test again.
I know I can do a for loop and do the check. However considering size difference and recurrence of the job, I am looking for a smart and efficient way to do it.
If you are not going to change content of vec, create an std::unordered_set<A*> with the same content and search for occurrences there. Searching in an unordered_set is approximately O(1), so this would be a simple win.
The easiest and the most efficient way to construct an unordered_set from a vector is to use the constructor taking two iterators:
unordered_set<A*> us(vec.begin(), vec.end());
You can use an unordered_set (you don't really need a map) which allows O(1) search and insert.
1) From vec you build an unordered_set<A*> S;
2) For each pair in vec_pair you can check if both elements are present in S
Something like the following will do the job in average O(vec_pair.size())
std::vector<A*> vec;
std::vector<std::pair<A*, A*>> vec_pair;
unordered_set<A*> S;
for(auto a: vec)
S.insert(a);
for(auto p : vec_pair){
if(s.find(p.first)!=S.end() &&
s.find(p.second)!=S.end())
{
//PAIR GOOD
}else{
//THIS PAIR IS NOT GOOD
}
}
vec_pair size is much more than vec size.
This should act as a clue to you to use std::map.
Put all the elements of vector vec inside a map : myMap[vec[i]] = 1;
Then go through each pair in vec_pair, and do
if (myMap.find(vec_pair[i].first != myMap.end()) &&
myMap.find(vec_pair[i].second != myMap.end()) )
{
return FOUND;
}
else
return NOT_FOUND;`
As commented by Gates, use unordered_map for faster operations.
I don't know yours exactly requirements but, if the order of element in vec_pair isn't important, I suppose you can substitute it with a std::multimap or, I suppose better, a std::unordered_multimap.
I mean (using a type A equal to int as example) that instead
using A = int;
std::vector<std::pair<A, A>> const vec_pair
{ {1, 1}, {1, 2}, {1, 3}, {1, 4},
{2, 1}, {2, 2}, {2, 3}, {2, 4},
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{4, 1}, {4, 2}, {4, 3}, {4, 4} };
you can use
std::unordered_multimap<A, A> const cM
{ {1, 1}, {1, 2}, {1, 3}, {1, 4},
{2, 1}, {2, 2}, {2, 3}, {2, 4},
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{4, 1}, {4, 2}, {4, 3}, {4, 4} };
If you need that vec_pair is a vector of pairs, using the fact that vec_pair is constant (I understand correctly?) you can contruct a constant unordered multimap.
The advantage of this solution is that if you find that a key of the map isn't in vec, you can avoid the test for all the values with the same key.
More: if construct a set (or, better, an unordered_set) starting from vec (that is little, if I understand correctly, you can check the pairs as follows
for ( auto ci = cM.cbegin() ; ci != cM.cend() ; )
{
auto val = ci->first;
auto cnt = cM.count(val);
if ( s.end() == s.find(val) )
{
for ( auto i = 0U ; i < cnt ; ++i )
++ci;
}
else for ( auto i = 0U ; i < cnt ; ++i, ++ci )
if ( s.end() != s.find(ci->second) )
std::cout << "- good for <" << val << ", " << ci->second
<< '>' << std::endl;
}
I know: isn't an elegant solution.
Another way is to use a combination of map and set (unorderd, better) and instead of
std::vector<std::pair<A, A>> const vec_pair
{ {1, 1}, {1, 2}, {1, 3}, {1, 4},
{2, 1}, {2, 2}, {2, 3}, {2, 4},
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{4, 1}, {4, 2}, {4, 3}, {4, 4} };
use (or construct)
std::unordered_map<A, std::unordered_set<A>> const cM
{ {1, {1, 2, 3, 4}}, {2, {1, 2, 3, 4}},
{3, {1, 2, 3, 4}}, {4, {1, 2, 3, 4}} };
In this case, the search part is more elegant (IMHO)
for ( auto const & p : cM2 )
if ( s.end() != s.find(p.first) )
for ( auto const & sec : p.second )
if ( s.end() != s.find(sec) )
std::cout << "- good for <" << p.first << ", " << sec
<< '>' << std::endl;
The following is a full compilable example for both solutions
#include <vector>
#include <utility>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
int main()
{
using A = int;
std::unordered_multimap<A, A> const cM
{ {1, 1}, {1, 2}, {1, 3}, {1, 4},
{2, 1}, {2, 2}, {2, 3}, {2, 4},
{3, 1}, {3, 2}, {3, 3}, {3, 4},
{4, 1}, {4, 2}, {4, 3}, {4, 4} };
std::unordered_set<A> s { 4, 3 };
for ( auto ci = cM.cbegin() ; ci != cM.cend() ; )
{
auto val = ci->first;
auto cnt = cM.count(val);
if ( s.end() == s.find(val) )
{
for ( auto i = 0U ; i < cnt ; ++i )
++ci;
}
else for ( auto i = 0U ; i < cnt ; ++i, ++ci )
if ( s.end() != s.find(ci->second) )
std::cout << "- good for <" << val << ", " << ci->second
<< '>' << std::endl;
}
std::unordered_map<A, std::unordered_set<A>> const cM2
{ {1, {1, 2, 3, 4}}, {2, {1, 2, 3, 4}},
{3, {1, 2, 3, 4}}, {4, {1, 2, 3, 4}} };
for ( auto const & p : cM2 )
if ( s.end() != s.find(p.first) )
for ( auto const & sec : p.second )
if ( s.end() != s.find(sec) )
std::cout << "- good for <" << p.first << ", " << sec
<< '>' << std::endl;
}
How much smaller is vec than vec_pair? Is the square of the size of vec still much smaller than the size of vec_pair? If so, you make an unordered_set out of vec_pair, and then search it for every possible pair generated from two things from vec.
Why can't you sort the two containers? Can you make a sorted copy of each? If so, take a pointer to the start of both lists, and increment both looking for matches. You would still be O(size of vec_pair) but your constant would be really small -- often just a single pointer comparison.
I have a vector of structures {key; value}, sorted by key:
{ {0, 1}, {0, 2}, {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2} }
I need to erase all but the last elements with the same key. The result should be:
{ {0, 2}, {1, 3}, {2, 2} }
What is the most neat way to do this? Which STL algorithms can I use? Apparently, this task doesn't fit remove-erase idiom.
A naive but efficient solution is to iterate over the vector, copying the relevant elements into a new vector.
An alternative is to use std::unique (with an appropriate predicate). As you want to preserve the last element in each group, you'd need to use a reverse iterator.
I words, the algorithm needed would be:
iterate the container backwards
if you encoutner a new key, leave the element,
if you encoutner a key you already had, remove the element.
in code:
#include <vector>
#include <iostream>
#include <algorithm>
struct S { int key; int value; };
int main() {
std::vector<S> vec{ {0, 1}, {0, 2}, {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2} };
auto lastKey = std::numeric_limits<int>::max();
auto rLast = std::remove_if(vec.rbegin(), vec.rend(), [&lastKey](S const& s) -> bool {
if (s.key == lastKey) return true;
lastKey = s.key;
return false;
});
vec.erase(begin(vec),rLast.base());
for (auto& s : vec) {
std::cout << '{' << s.key << ',' << s.value << '}';
}
}
Or using std::unique as recommended in the other answer:
auto rLast = std::unique(vec.rbegin(), vec.rend() [](S const& s1, S const& s2) {
return s1.key == s2.key;
});
vec.erase(vec.begin(), rLast.base());
If you use an std::map the problem just disappears:
std::map<int, int> theMap;
// insert the elements of { {0, 1}, {0, 2}, {1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2} }
theMap[0] = 1;
theMap[0] = 2;
theMap[1] = 1;
theMap[1] = 2;
theMap[1] = 3;
theMap[2] = 1;
theMap[2] = 2;
// result: { {0, 2}, {1, 3}, {2, 2} }