I want to know how to sort the triple below based on the first column using C++?
Can I use std::map?
0 0 1
1 2 0
2 0 3
0 1 4
the wanted result is
0 0 1
0 1 4
1 2 0
2 0 3
You could just use std::sort on, for example, a vector of std::tuple - the default comparison is lexicographic, so first column counts most.
Assuming you are sorting a std::vector<std::vector<int>>
C++11:
std::sort(begin(vec), end(vec), [](const std::vector<int>& a,
const std::vector<int>& b){
return a[0] < b[0]; // sorting on the first column only
});
Assuming you want lexical order:
std::sort(begin(vec), end(vec));
Related
Suppose you have a 2D vector defined as follows:
std::vector<vector<int>> v
and which represents a matrix:
1 1 0 1 3
0 4 6 0 1
5 0 0 3 0
6 3 0 2 5
I want to stable-partition (say with predicate el != 0) this matrix, but in all directions. This means that I want to be able to get:
1 1 6 1 3 0 0 0 0 0 1 1 1 3 0 0 1 1 1 3
5 4 0 3 1 1 1 0 1 3 4 6 1 0 0 0 0 4 6 1
6 3 0 2 5 5 4 0 3 1 5 3 0 0 0 0 0 0 5 3
0 0 0 0 0 6 3 6 2 5 6 3 2 5 0 0 6 3 2 5
(down) (up) (right) (left)
For two directions, this can be done very simply by iterating through the outer vector and partitioning the inner vectors (in order or in reverse). However for the other directions I do not know how to go about doing the same.
Is there a way to achieve this using std::stable_partition. Is there maybe another data structure (which supports indexing like vectors) which will allow me to do this more easily?
If I have ti implement this by scratch, is there maybe a standard or recommended way to do it?
You don't need to write your own implementation of the algorithm. Iterators are the customization point when you want to use an existing algorithm for a custom data structure. Unfortunately, writing your own iterator requires quite some boilerplate. I think boost can help, but if you want to stay with what the standard library offers, to my knowledge there is no way around writing it yourself.
The following is to be taken with a grain of salt. I assume all inner vectors are of same size. I do not take into account const_iterators, because you wont need them to use std::stable_partition. I have omitted some member functions that you will have to add yourself. The algorithm requires the iterator to adhere to two named concepts, namely LegacyBidirectionalIterator and ValueSwappable. That being said, here is how you can implement an iterator that enables you to iterate columns of the 2d vector:
#include <iostream>
#include <vector>
struct vector2d_col_iterator {
using container_t = std::vector<std::vector<int>>;
container_t& container;
size_t row;
size_t col;
vector2d_col_iterator& operator++(){
++row;
return *this;
}
bool operator==(const vector2d_col_iterator& other) const {
return col == other.col && row == other.row;
}
bool operator !=(const vector2d_col_iterator& other) const {
return !(*this == other);
}
int& operator*() { return container[row][col]; }
static vector2d_col_iterator begin(container_t& container,int col) {
return {container,0,col};
}
static vector2d_col_iterator end(container_t& container,int col) {
return {container,container.size(),col};
}
};
int main() {
std::vector<std::vector<int>> v{ {1,2,3},{4,5,6}};
auto begin = vector2d_col_iterator::begin(v,1);
auto end = vector2d_col_iterator::end(v,1);
for ( ; begin != end; ++begin) std::cout << *begin << " ";
}
Output:
2 5
Live example
Efficiency is not a really big issue, the matrices will be relatively small. I just want to find the simplest, clearest way of doing this. Preferably without having to write a stable_partition implementation from scratch.
If the matrices are really small (lets say ~20x20 elements) and efficiency is really not a concern, then the simplest is perhaps to use std::stable_partition only on the inner vectors. You can transpose the matrix, call the algorithm in a loop for all inner vectors, transpose again. Done. Thats basically ~10 lines of code. Your choice ;)
With range-v3, you might do:
const std::vector<std::vector<int>> v = /*..*/;
auto is_zero = [](int e){ return e == 0; };
auto right = v;
for (auto& row : right) {
ranges::stable_partition(row | ranges::view::reverse, is_zero);
}
print(right);
auto top = v;
for (std::size_t i = 0; i != v[0].size(); ++i) {
auto col_view = top | ranges::view::transform([i](auto& row)-> int& { return row[i]; });
ranges::stable_partition(col_view, is_zero);
}
print(top);
Demo
Sorry if this is a duplicate, but I did not find any answers which match mine.
Consider that I have a vector which contains 3 values. I want to construct another vector of a specified length from this vector. For example, let's say that the length n=3 and the vector contains the following values 0 1 2. The output that I expect is as follows:
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2
1 2 0
1 2 1
1 2 2
2 0 0
2 0 1
2 0 2
2 1 0
2 1 1
2 1 2
2 2 0
2 2 1
2 2 2
My current implementation simply constructs for loops based on nand generates the expected output. I want to be able to construct output vectors of different lengths and with different values in the input vector.
I have looked at possible implementations using next_permutation, but unfortunately passing a length value does not seem to work.
Are there time and complexity algorithms that one can use for this case? Again, I might have compute this for up to n=17and sizeof vector around 6.
Below is my implementation for n=3. Here, encis the vector which contains the input.
vector<vector<int> > combo_3(vector<double>enc,int bw){
vector<vector<int> > possibles;
for (unsigned int inner=0;inner<enc.size();inner++){
for (unsigned int inner1=0;inner1<enc.size();inner1++){
for (unsigned int inner2=0;inner2<enc.size();inner2++){
cout<<inner<<" "<<inner1<<" "<<inner2<<endl;
unsigned int arr[]={inner,inner1,inner2};
vector<int>current(arr,arr+sizeof(arr)/sizeof(arr[0]));
possibles.push_back(current);
current.clear();
}
}
}
return possibles;
}
What you are doing is simple counting. Think of your output vector as a list of a list of digits (a vector of a vector). Each digit may have one of m different values where m is the size of your input vector.
This is not permutation generation. Generating every permutation means generating every possible ordering of an input vector, which is not what you're looking for at all.
If you think of this as a counting problem the answer may become clearer to you. For example, how would you generate all base 10 numbers with 5 digits? In that case, your input vector has size 10, and each vector in your output list has length 5.
Why is the vector 'r' giving the output as follows? Instead, it should not have zero in the list.
Can someone help?
output: 0 0 0 0 0 5 1 2 3 4
vector <int> leftRotation(vector <int> a, int d) {
vector<int> r(a.size());
// int j=0;
for(int i=d; i<a.size(); i++)
r.push_back(a[i]);
for(int i=0; i<d; i++)
r.push_back(a[i]);
return r;
}
You are initializing r with a.size() copies of 0 at the start of your code:
vector<int> r(a.size());
At this point, the vector r contains values 0 0 0 0 0 (as many zeroes as there are elements in a).
Then, you push values onto the back of this vector of zeroes. At each step of your loops:
0 0 0 0 0 5
0 0 0 0 0 5 1
0 0 0 0 0 5 1 2
0 0 0 0 0 5 1 2 3
0 0 0 0 0 5 1 2 3 4
Instead, initialize with an empty vector:
vector<int> r;
The local variable of vector<int> r(a.size()) uses a vector's constructor overload that accepts (size_type count) argument and is initialized (or rather zeroed out) to contain a.size() number of 0s. For clarification check out the std::vector constructor overload no. 3:
The overload (3) zeroes out elements of non-class types such as int
Use a default constructor to create an empty container instead:
std::vector<int> r;
or:
std::vector<int> r{};
vector<int> r(a.size());
With this line, you create a vector of initial size a.size(); the initial elements in the vector are set to 0.
Probably your a vector has size 5, so this is where the five zeros in your output come from:
0 0 0 0 0
Then, you invoke the push_back() method on r, and this appends other elements at the end of the r vector.
To get a better help, please clarify your goal.
I've created a map having a vector as below:
map<int,vector<int>> mymap;
How can I sort this map according to the nth value of the vector contained by map?
You can't. You can provide a custom comparator to make the underlying data get sorted another way than the default, but this only relates to keys, not values. If you have a requirement for your container's elements to exist in some specific, value-defined order, then you're using the wrong container.
You can switch to a set, and take advantage of the fact that there is no distinction there between "key" and "value", and hack the underlying sorting yourself:
template <std::size_t N>
struct MyComparator
{
typedef std::pair<int, std::vector<int>> value_type;
bool operator()(const value_type& lhs, const value_type& rhs)
{
return lhs.second.at(N) < rhs.second.at(N);
}
};
/**
* A set of (int, int{2,}) pairs, sorted by the 2nd element in
* the 2nd item of each pair.
*/
std::set<std::pair<int, std::vector<int>>, MyComparator<1>> my_data;
int main()
{
my_data.insert(std::make_pair(1, std::vector<int>{0,5,0,0}));
my_data.insert(std::make_pair(2, std::vector<int>{0,2,0,0}));
my_data.insert(std::make_pair(3, std::vector<int>{0,1,0,0}));
my_data.insert(std::make_pair(4, std::vector<int>{0,9,0,0}));
for (const auto& el : my_data)
std::cout << el.first << ' ';
}
// Output: 3 2 1 4
(live demo)
However, if you still need to perform lookup on key as well, then you're really in trouble and need to rethink some things. You may need to duplicate your data or provide an indexing vector.
map<int,vector<int>> mymap;
How can i sort this map according to the nth value of the vector contained by map?
That's only possible if you're prepared to use that nth value as the integer key too, as in consistently assigning:
mymap[v[n - 1]] = v;
If you're doing that, you might consider a set<vector<int>>, which removes the redundant storage of that "key" element - you would then need to provide a custom comparison though....
If you envisage taking an existing populated map that doesn't have that ordering, then sorting its elements - that's totally impossible. You'll have to copy the elements out to another container, such as a set that's ordered on the nth element, or a vector that you std::sort after populating.
If I have understood correctly you can (build) add elements to the map the following way
std::vector<int> v = { 1, 2, 3 };
std::vector<int>::size_type n = 2;
mymap[v[n]] = v;
Here is an example
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <ctime>
int main()
{
std::srand( ( unsigned )time( 0 ) );
const size_t N = 10;
std::map<int, std::vector<int>> m;
for ( size_t i = 0; i < N; i++ )
{
std::vector<int> v( N );
std::generate( v.begin(), v.end(), []{ return std::rand() % N; } );
m[v[0]] = v;
}
for ( auto &p : m )
{
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
0 1 7 8 1 2 9 0 0 9
1 6 3 1 3 5 0 3 1 5
3 8 0 0 0 7 1 2 9 7
5 9 5 0 7 1 2 0 6 3
6 4 7 5 4 0 0 4 2 0
7 9 8 6 5 5 9 9 4 5
8 3 8 0 5 9 6 6 8 3
9 5 4 7 4 0 3 5 1 9
Take into account that as there can be duplicated vectors (that is that have the same value of the n-th element (in my example n is equal to 0) then some vectors will not be added to the map. If you want to have duplicates then you should use for example std::multimap
Also you can build a new map according to the criteria based on an existent map.
You can abuse the fact a c++ map uses a tree sorted by its keys. This means that you can either create a new map, with as keys the values you wish it to be sorted on, but you can also create a vector with references to the items in your map, and sort that vector (or the other way around: you could have a sorted vector, and use a map to create an index on your vector). Be sure to use a multimap in the case of duplicate keys.
dear all,
i have a map, defined as map<int, vector<int> > my_map. So, for example it looks like as follows,
my_map=
0 1 2 6 5 4
1 0 2 3 4 5
2 0 1 4
3 1
4 1 2 0 7 5 6
5 1 0 6 4
6 0 5 4
7 4
vector<int> element_common(map<int, vector<int> > &my_map, int s1, int s2){
vector<int> common2;
vector<int> first_vector=my_map[s1];
vector<int>::iterator snd_vector_begin= my_map[s2].begin();
vector<int>::iterator snd_vector_end= my_map[s2].end();
for (vector<int>::iterator any=first_vector.begin();
any!=first_vector.end();
any++){
// check if any is in other_list
vector<int>::iterator any_in_snd_vector_iterator= find (snd_vector_begin,snd_vector_end, *any);
if(any_in_snd_vector_iterator==snd_vector_end){
common2.push_back(*any);
}
}
return common2;
i wrote a function above function to get common elements from the vector parts which are relevant to 2 given keys. when keys are equal to s1 and s2, i.e. s1=1 and s2=4. then my function should give me 0,2,5. but i got 3,4. please help me to rectify my function.
If you can guarantee your vectors are sorted then you can improve your performance substantially from O(mn) to O(m + n):
std::vector<int> common;
std::set_intersection(vec1.begin(), vec1.end(),
vec2.begin(), vec2.end(),
std::back_inserter(common));
You got the test exactly backwards:
if(any_in_2nd_vector_iterator==2nd_vector_end){
is true when the element ISN'T FOUND in the second vector. Try !=.
Then, you can avoid needless copying of vectors by using a reference:
const vector<int>& first_vector=my_map[s1];
and if your vectors get much larger, it may be faster to do a hash lookup (or pre-sorted merge if the vectors are always kept sorted) instead of a call to find which has to check every element.