How to sort vector<vector<int>>? [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have a vector:
vector<vector<int>> myvector;
How can I sort this vector in an order as in alphabethical order for strings?
e.g. Output:
Unsorted:
5 9 4 12 4
7 9 3 4 7 9
6 5 11
5 8 7 3
5 9 5 1 1
Sorted:
7 9 3 4 7 9
6 5 11
5 9 5 1 1
5 9 4 12 4
5 8 7 3

Just use the std::sort algorithm. The only subtlety is that it sorts in descending order, so you need to change the sorting criteria. Two ways to do this spring to mind.
Use a custom comparison functor, e.g. std::greater:
std::sort(v.begin(), v.end(), std::greater<std::vector<int>>());
Use reverse iterators:
std::sort(myvector.rbegin(), myvector.rend());
The former version makes the intent clearer, whereas the latter may require some head scratching and documentation reading. But the result is the same for both.
Here's a working example:
#include <vector>
#include <algorithm> // for std::sort
#include <functional> // for std::greater
#include <iostream>
int main()
{
// Set up an example vector
std::vector<std::vector<int>> v{{5, 9, 4, 12, 4},
{7, 9, 3, 4, 7, 9},
{6, 5, 11},
{5, 8, 7, 3},
{5, 9, 5, 1, 1}};
// Perform the sort
std::sort(v.begin(), v.end(), std::greater<std::vector<int>>());
// Output the results
for (const auto& i : v)
{
for (auto j : i)
std::cout << j << " ";
std::cout << "\n";
}
}
Output:
7 9 3 4 7 9
6 5 11
5 9 5 1 1
5 9 4 12 4
5 8 7 3

Related

C++ Sort vector by index

I need to sort a std::vector by index. Let me explain it with an example:
Imagine I have a std::vector of 12 positions (but can be 18 for example) filled with some values (it doesn't have to be sorted):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3
I want to sort it every 3 index. This means: the first 3 [0-2] stay, then I need to have [6-8] and then the others. So it will end up like this (new index 3 has the value of previous idx 6):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 1 2 2 3 2 0 4 5 3
I'm trying to make it in one line using std::sort + lambda but I can't get it. Also discovered the std::partition() function and tried to use it but the result was really bad hehe
Found also this similar question which orders by odd and even index but can't figure out how to make it in my case or even if it is possible: Sort vector by even and odd index
Thank you so much!
Note 0: No, my vector is not always sorted. It was just an example. I've changed the values
Note 1: I know it sound strange... think it like hte vecotr positions are like: yes yes yes no no no yes yes yes no no no yes yes yes... so the 'yes' positions will go in the same order but before the 'no' positions
Note 2: If there isn't a way with lambda then I thought making it with a loop and auxiliar vars but it's more ugly I think.
Note 3: Another example:
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3 2 3 0 0 2 1
Sorted Values: 3 0 2 1 2 2 2 3 0 3 2 0 4 5 3 0 2 1
The final Vector Values is sorted (in term of old index): 0 1 2 6 7 8 12 13 14 3 4 5 9 10 11 15 16 17
You can imagine those index in 2 colums, so I want first the Left ones and then the Right one:
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
You don't want std::sort, you want std::rotate.
std::vector<int> v = {20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31};
auto b = std::next(std::begin(v), 3); // skip first three elements
auto const re = std::end(v); // keep track of the actual end
auto e = std::next(b, 6); // the end of our current block
while(e < re) {
auto mid = std::next(b, 3);
std::rotate(b, mid, e);
b = e;
std::advance(e, 6);
}
// print the results
std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, " "));
This code assumes you always do two groups of 3 for each rotation, but you could obviously work with whichever arbitrary ranges you wanted.
The output looks like what you'd want:
20 21 22 26 27 28 23 24 25 29 30 31
Update: #Blastfurnace pointed out that std::swap_ranges would work as well. The rotate call can be replaced with the following line:
std::swap_ranges(b, mid, mid); // passing mid twice on purpose
With the range-v3 library, you can write this quite conveniently, and it's very readable. Assuming your original vector is called input:
namespace rs = ranges;
namespace rv = ranges::views;
// input [3, 0, 2, 3, 2, 0, 1, 2, 2, 4, 5, 3, 2, 3, 0, 0, 2, 1]
auto by_3s = input | rv::chunk(3); // [[3, 0, 2], [3, 2, 0], [1, 2, 2], [4, 5, 3], [2, 3, 0], [0, 2, 1]]
auto result = rv::concat(by_3s | rv::stride(2), // [[3, 0, 2], [1, 2, 2], [2, 3, 0]]
by_3s | rv::drop(1) | rv::stride(2)) // [[3, 2, 0], [4, 5, 3], [0, 2, 1]]
| rv::join
| rs::to<std::vector<int>>; // [3, 0, 2, 1, 2, 2, 2, 3, 0, 3, 2, 0, 4, 5, 3, 0, 2, 1]
Here's a demo.

Extracting Columns From a Vector Matrix to store in an Array

Problem Explanation
Edit: Solution is added to the bottom in case anyone needs it
Let's Say I have a matrix with following data
1 3 2 1 7 9 5 8
9 1 3 8 6 9 4 1
3 2 4 0 4 5 7 4
3 5 6 4 6 5 7 4
I want to define a size_of_chunks variable that will store the number of chunks for example if I set size_of_chunks=2 then the matrix will become
Chunk1 | Chunk2 | Chunk3 | Chunk4
-------|---------|--------|-------
1 3 | 2 1 | 7 9 | 5 8
9 1 | 3 8 | 6 9 | 4 1
3 2 | 4 0 | 4 5 | 7 4
3 5 | 6 4 | 6 5 | 7 4
I want to take one of these chunks and use push_back to a std::vector<int>temp(row*col);
Chunk1 |
---------|
Start-> 1 3 |
9 1 |
3 2 |
End-> 3 5 |
so the temp will look like the following:
temp = {1, 3, 9, 1, 3, 2, 3, 5}
Later on when I did the same steps to chunk 2 the temp will look like this:
temp = {1, 3, 9, 1, 3, 2, 3, 5, 2, 1, 3, 8, 4, 0, 6, 4}
Code
int row = 4;
int col = 8;
int size_of_chunk = 2;
std::vector<int> A(row*col);
std::vector<int> temp(row*col);
// Here a Call for the Function to Fill A with Data
for(int r=0;r<row;r++){
for(int c=0;c<col;c+=size_of_chunk){
for(int i=0;i<c;i++){
temp.push_back(A[r*col+i]);
}
}
}
It's giving me values that doesn't match to end results how should I approach this problem ?
Thank you!
Solution
for(int c=0;c<col;c+=size_of_chunk){
for(int r=0;r<row;r++){
for(int i=0;i<size_of_chunk;i++){
temp.push_back(A[r*col+i+c]);
}
}
}
Don't specify a size for the vector in the constructor and use push_back, because that way you end up with a vector twice as big as it should be. Do one or the other.
In this case presumably it should be
std::vector<int> temp;
That is, start the vector at size zero and increase it's size using push_back.

Is it safe to traverse a container during std::remove_if execution?

Suppose I want to remove the unique elements from an std::vector (not get rid of the duplicates, but retain only the elements that occur at least 2 times) and I want to achieve that in a pretty inefficient way - by calling std::count while std::remove_ifing. Consider the following code:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
return std::count(vec.begin(), vec.end(), n) == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
From reference on std::remove_if we know that the elements beginning from to_remove have unspecified values, but I wonder how unspecified they can really be.
To explain my concern a little further - we can see that the elements that should be removed are 1, 3, 5 and 7 - the only unique values. std::remove_if will move the 1 to the end but there is no guarantee that there will be a value 1 at the end after said operation. Can this be (due to that value being unspecified) that it will turn into 3 and make the std::count call return a count of (for example) 2 for the later encountered value 3?
Essentially my question is - is this guaranteed to work, and by work I mean to inefficiently erase unique elements from an std::vector?
I am interested in both language-lawyer answer (which could be "the standard says that this situation is possible, you should avoid it") and in-practice answer (which could be "the standard says that this situation is possible, but realistically there is no way of this value ending up as a completely differeny one, for example 3").
After the predicate returns true the first time, there will be one unspecified value in the range. That means any subsequent calls of the predicate will count an unspecified value. The count is therefore potentially incorrect, and you may either leave values unaffected that you intend to be discarded, or discard values that should be retained.
You could modify the predicate so it keeps a count of how many times it has returned true, and reduce the range accordingly. For example;
std::size_t count = 0;
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec, &count](int n)
{
bool once = (std::count(vec.begin(), vec.end() - count, n) == 1);
if (once) ++count;
return once;
});
Subtracting an integral value from a vector's end iterator is safe, but that isn't necessarily true for other containers.
You misunderstood how std::remove_if works. The to-be-removed values are not necessarily shifted to the end. See:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. cppreference
This is the only guarantee for the state of the range. According to my knowledge, it's not forbidden to shift all values around and it would still satisfy the complexity. So it might be possible that some compilers shift the unwanted values to the end but that would be just extra unnecessary work.
An example of possible implementation of removing odd numbers from 1 2 3 4 8 5:
v - read position
1 2 3 4 8 5 - X will denotes shifted from value = unspecified
^ - write position
v
1 2 3 4 8 5 1 is odd, ++read
^
v
2 X 3 4 8 5 2 is even, *write=move(*read), ++both
^
v
2 X 3 4 8 5 3 is odd, ++read
^
v
2 4 3 X 8 5 4 is even, *write=move(*read), ++both
^
v
2 4 8 X X 5 8 is even, *write=move(*read), ++both
^
2 4 8 X X 5 5 is odd, ++read
^ - this points to the new end.
So, in general, you cannot rely on count returning any meaningful values. Since in the case that move==copy (as is for ints) the resulting array is 2 4 8|4 8 5. Which has incorrect count both for the odd and even numbers. In case of std::unique_ptr the X==nullptr and thus the count for nullptr and removed values might be wrong. Other remaining values should not be left in the end part of the array as there were no copies done.
Note that the values are not unspecified as in you cannot know them. They are exactly the results of move assignments which might leave the value in unspecified state. If it specified the state of the moved-from variables ( asstd::unique_ptr does) then they would be known. E.g. if move==swap then the range will be permuted only.
I added some outputs:
#include <algorithm>
#include <iostream>
#include <vector>
#include <mutex>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
std::cout << "number " << n << ": ";
for (auto i : vec) std::cout << i << ' ';
auto c = std::count(vec.begin(), vec.end(), n);
std::cout << ", count: " << c << std::endl;
return c == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
and got
number 1: 1 2 6 3 6 2 7 4 4 5 6 , count: 1
number 2: 1 2 6 3 6 2 7 4 4 5 6 , count: 2
number 6: 2 2 6 3 6 2 7 4 4 5 6 , count: 3
number 3: 2 6 6 3 6 2 7 4 4 5 6 , count: 1
number 6: 2 6 6 3 6 2 7 4 4 5 6 , count: 4
number 2: 2 6 6 3 6 2 7 4 4 5 6 , count: 2
number 7: 2 6 6 2 6 2 7 4 4 5 6 , count: 1
number 4: 2 6 6 2 6 2 7 4 4 5 6 , count: 2
number 4: 2 6 6 2 4 2 7 4 4 5 6 , count: 3
number 5: 2 6 6 2 4 4 7 4 4 5 6 , count: 1
number 6: 2 6 6 2 4 4 7 4 4 5 6 , count: 3
2 6 6 2 4 4 6
As you can see the counts can be wrong. I'm not able to create an example for your special case but as a rule you have to worry about wrong results.
First the number 4 is counted twice and in the next step the number 4 is counted thrice. The counts are wrong and you can't rely on them.

C++ random_shuffle is always giving the same results

The following call for random shuffle is always giving the same results for the vector v
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
int main(){
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
srand(time(0));
random_shuffle(v.begin(), v.end());
for (int i = 0; i < v.size(); ++i) printf("%d ", v[i]); printf("\n");
printf("%d\n", rand() % 100);
return 0;
}
I've tried compiling using
g++ -std=c++0x
g++ -std=c++11
But both give the same results every time so I don't really understand what's going on.
$./a.out
7 1 4 6 8 9 5 2 3 10
26
$ ./a.out
7 1 4 6 8 9 5 2 3 10
41
$ ./a.out
7 1 4 6 8 9 5 2 3 10
39
OP's comment makes it clear that this is Clang and libc++ that they are using, not GCC/libstdc++.
A quick look at libc++'s random_shuffle implementation shows that it uses an object of type __rs_default as its source of randomness, and inspecting the implementation of __rs_default shows that it simply uses a default-constructed std::mt19937 object:
__rs_default::result_type
__rs_default::operator()()
{
static mt19937 __rs_g;
return __rs_g();
}
In other words, in this implementation srand has no effect whatsoever on the source of "randomness" used by the two-parameter version of random_shuffle. (Scary quotes because it always uses a fixed seed.) Note that random_shuffle is not required to use rand at all, so you can't expect srand to "work" in portable code anyway.
Use std::shuffle and the <random> facilities instead.
Firstly, -std=c++0x and -std=c++11 mean exactly the same thing, so testing both is pointless.
You didn't provide a complete program (please read https://stackoverflow.com/help/mcve next time) so I guessed at the rest of your code, and I tried this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>
using namespace std;
int main()
{
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
srand(time(0));
random_shuffle(v.begin(), v.end());
for (int i : v)
std::cout << i << ' ';
std::cout << std::endl;
}
I get different results every second:
tmp$ ./a.out
2 1 8 5 9 7 6 3 10 4
tmp$ ./a.out
10 7 6 3 1 8 9 4 5 2
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2
tmp$ ./a.out
4 7 3 6 5 8 1 9 10 2
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1
tmp$ ./a.out
10 2 6 3 9 4 5 7 8 1
tmp$ ./a.out
2 1 3 7 5 8 9 6 4 10
The times when it produces the same result are because the number of seconds returned by time(0) is the same, and so the seed for the rand() function is the same, and so the results are the same. If you wait a second so that time(0) returns a different value you should get a different random shuffle of the elements.
If the code you are running is not the same as mine you might get different results, but we can't possibly explain the results because you didn't show us your code.

Striding windows

Assume that I have a vector:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
What I need to do is split this vector into block sizes of blocksize with an overlap
blocksize = 4
overlap = 2
The result, would be a 2D vector with size 4 containing 6 values.
x[0] = [1, 3, 5, 7, 9, 11]
x[1] = [ 2 4 6 8 10 12]
....
I have tried to implement this with the following functions:
std::vector<std::vector<double> > stride_windows(std::vector<double> &data, std::size_t
NFFT, std::size_t overlap)
{
std::vector<std::vector<double> > blocks(NFFT);
for(unsigned i=0; (i < data.size()); i++)
{
blocks[i].resize(NFFT+overlap);
for(unsigned j=0; (j < blocks[i].size()); j++)
{
std::cout << data[i*overlap+j] << std::endl;
}
}
}
This is wrong, and, segments.
std::vector<std::vector<double> > frame(std::vector<double> &signal, int N, int M)
{
unsigned int n = signal.size();
unsigned int num_blocks = n / N;
unsigned int maxblockstart = n - N;
unsigned int lastblockstart = maxblockstart - (maxblockstart % M);
unsigned int numbblocks = (lastblockstart)/M + 1;
std::vector<std::vector<double> > blocked(numbblocks);
for(unsigned i=0; (i < numbblocks); i++)
{
blocked[i].resize(N);
for(int j=0; (j < N); j++)
{
blocked[i][j] = signal[i*M+j];
}
}
return blocked;
}
I wrote this function, thinking that it did the above, however, it will just store:
X[0] = 1, 2, 3, 4
x[1] = 3, 4, 5, 6
.....
Could anyone please explain how I would go about modifying the above function to allow for skips by overlap to take place?
This function is similar to this: Rolling window
EDIT:
I have the following vector:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
I want to split this vector, into sub-blocks (thus creating a 2D vector), with an overlap of the parameter overlap so in this case, the parameters would be: size=4 overlap=2, this would then create the following 2D vector:
`block0 = [ 1 3 5 7 9 11]
block1 = [ 2 4 6 8 10 12]
block2 = [ 3 5 7 9 11 13]
block3 = [ 4 6 8 10 12 14]`
So essentially, 4 blocks have been created, each block contains a value where the element is skipped by the overlap
EDIT 2:
This is where I need to get to:
The value of overlap will overlap the results of x in terms of placements inside the vector:
block1 = [1, 3, 5, 7, 9, 11]
Notice from the actual vector block:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
Value: 1 -> This is pushed into block "1"
Value 2 -> This is not pushed into block "1" (overlap is skip 2 places in the vector)
Value 3 -> This is pushed into block "1"
value 4 -> This is not pushed into block "1" (overlap is skip to places in the vector)
value 5 -> This is pushed into block "1"
value 6 -> "This is not pushed into block "1" (overlap is skip 2 places in the vector)
value 7 -> "This value is pushed into block "1"
value 8 -> "This is not pushed into block "1" (overlap is skip 2 places in the vector)"
value 9 -> "This value is pushed into block "1"
value 10 -> This value is not pushed into block "1" (overlap is skip 2 places in the
vector)
value 11 -> This value is pushed into block "1"
BLOCK 2
Overlap = 2;
value 2 - > Pushed back into block "2"
value 4 -> Pushed back into block "2"
value 6, 8, 10 etc..
So each time, the place in the vector is skipped by the "overlap" in this case, it is the value of 2..
This is what the expected output would be:
[[ 1 3 5 7 9 11]
[ 2 4 6 8 10 12]
[ 3 5 7 9 11 13]
[ 4 6 8 10 12 14]]
If I understand you correctly, you're pretty close. You need something like the following. I used int because frankly its easier to type than double =P
#include <iostream>
#include <algorithm>
#include <vector>
#include <limits>
#include <iterator>
std::vector<std::vector<int>>
split(const std::vector<int>& data, size_t blocksize, size_t overlap)
{
// compute maximum block size
std::vector<std::vector<int>> res;
size_t minlen = (data.size() - blocksize)/overlap + 1;
auto start = data.begin();
for (size_t i=0; i<blocksize; ++i)
{
res.emplace_back(std::vector<int>());
std::vector<int>& block = res.back();
auto it = start++;
for (size_t j=0; j<minlen; ++j)
{
block.push_back(*it);
std::advance(it,overlap);
}
}
return res;
}
int main()
{
std::vector<int> data { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
for (size_t i=2; i<6; ++i)
{
for (size_t j=2; j<6; ++j)
{
std::vector<std::vector<int>> blocks = split(data, i, j);
std::cout << "Blocksize = " << i << ", Overlap = " << j << std::endl;
for (auto const& obj : blocks)
{
std::copy(obj.begin(), obj.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
std::cout << std::endl;
}
}
return 0;
}
Output
Blocksize = 2, Overlap = 2
1 3 5 7 9 11 13
2 4 6 8 10 12 14
Blocksize = 2, Overlap = 3
1 4 7 10 13
2 5 8 11 14
Blocksize = 2, Overlap = 4
1 5 9 13
2 6 10 14
Blocksize = 2, Overlap = 5
1 6 11
2 7 12
Blocksize = 3, Overlap = 2
1 3 5 7 9 11
2 4 6 8 10 12
3 5 7 9 11 13
Blocksize = 3, Overlap = 3
1 4 7 10
2 5 8 11
3 6 9 12
Blocksize = 3, Overlap = 4
1 5 9
2 6 10
3 7 11
Blocksize = 3, Overlap = 5
1 6 11
2 7 12
3 8 13
Blocksize = 4, Overlap = 2
1 3 5 7 9 11
2 4 6 8 10 12
3 5 7 9 11 13
4 6 8 10 12 14
Blocksize = 4, Overlap = 3
1 4 7 10
2 5 8 11
3 6 9 12
4 7 10 13
Blocksize = 4, Overlap = 4
1 5 9
2 6 10
3 7 11
4 8 12
Blocksize = 4, Overlap = 5
1 6 11
2 7 12
3 8 13
4 9 14
Blocksize = 5, Overlap = 2
1 3 5 7 9
2 4 6 8 10
3 5 7 9 11
4 6 8 10 12
5 7 9 11 13
Blocksize = 5, Overlap = 3
1 4 7 10
2 5 8 11
3 6 9 12
4 7 10 13
5 8 11 14
Blocksize = 5, Overlap = 4
1 5 9
2 6 10
3 7 11
4 8 12
5 9 13
Blocksize = 5, Overlap = 5
1 6
2 7
3 8
4 9
5 10