0

I have a project that required me to read and sort values read from a .csv files by a certain column. I'm using the algorithm library in C++ i.e #include <algorithm> The library has the function sort() which I plan on utilizing. It required me to specify the beginning and the end e.g for a 2d vector called vect it would require vect.begin() as well as vect.end(). My question is, is it possible to specify the exact start position and end position for the sort() function. That is like start at vect[1][0] and end at vect[9][9].

Thanks for your help

  • 3
    You can't `std::sort` 2D vectors/arrays. What result would you expect from doing it? – HolyBlackCat Feb 13 '18 at 12:18
  • If `vect.begin()` is the first element of the vector (assuming it's not empty), then what do you think `vect.begin() + 1` is? – Some programmer dude Feb 13 '18 at 12:18
  • Indirect-sort the column and then use the index to access the rows. See an example here: https://stackoverflow.com/questions/48764471/sorting-one-vector-with-respect-to-another-most-efficient-way/48766460#48766460 – Maxim Egorushkin Feb 13 '18 at 12:23
  • @HolyBlackCat Well it worked when I sorted values based on one column although it also moved the header of the table to the bottom and that's what I'm trying to avoid – Daniel Wole Olamide Feb 13 '18 at 12:24
  • @Someprogrammerdude Lemme try that and let you know – Daniel Wole Olamide Feb 13 '18 at 12:24
  • 1
    @HolyBlackCat : Of course you can sort a 2D vector. The natural definition of a sorted vector of vectors is that the result has the inner vectors stored in lexographical order (so [[4, 5, 6], [1, 2, 3], [1, 2, 4]] would be output as [[1, 2, 3], [1, 2, 4], [4, 5, 6]]). Of course, in practise, `std::vector` doesn't have an `operator <` defined. The OP will need a customer comparison functor anyway to select the column. – Martin Bonner supports Monica Feb 13 '18 at 12:27
  • There's this beautifully written ["Iterator of a Container of Containers"](https://codereview.stackexchange.com/questions/186544/iterator-of-container-of-container) piece posted on Code Review. It's only a forward iterator, but I'm sure it can get you started on creating a simulated random access iterator for the vector of vectors case. Which is what you'll need to `std::sort` it. – StoryTeller - Unslander Monica Feb 13 '18 at 13:17
  • @MartinBonner it doesn't have a *member* `<`, but it does have [`<`](http://en.cppreference.com/w/cpp/container/vector/operator_cmp) – Caleth Feb 13 '18 at 13:39

3 Answers3

1

I'm assuming for sake of discussion you are working with a std::vector<std::vector<int> >. The same discussion applies for a 2D vector of other types.

If you want to sort the individual ints so they are ordered within the std::vector<std::vector<int> > then it's not possible to do directly. There is no iterator that can be obtained directly from a std::vector<std::vector<int>> which runs over all of the nested ints.

One way might be to set up a temporary copy into a std::vector<int> (i.e. create a flattened 1D vector), sort that, and then copy the elements back. For example;

 std::vector<std:vector<int> > vec;

   // populate vec somehow

 std::vector<int> elements(0);

 // create a single std::vector<int> from the vector<vector<int>> by
 //    appending the vector<int>s end to end

 for (const auto &row : vec)
 {
      elements.insert(elements.end(), row.begin(), row.end());
 }

 std::sort(elements.begin(), elements.end());   // sort in ascending order

 //   now copy the sorted elements back

 auto start = elements.begin();

 for (auto &row : vec)   //  non-const here since we seek to change the vector<int>s within vec
 {
      auto end = start + row.size();
      std::copy(start, end, row.begin());
      start = end;
 }

The shenanigans in the last loop with row.size() and row.begin() deals with the possibility that the vector<int> within vec are of different sizes, so will change

 {{5,6,7}, {1,2}, {3,4,8}}

to be

 {{1,2,3}, {4, 5}, {6,7,8}}

rather than to something else such as to

 {{1,2}, {3,4,5}, {6, 7, 8}};     //   vector<int>s resized

Things can be simplified a little if you assume all the inner vectors are of the same size.

Alternatively, you might try hand-rolling a struct/class type that has all the properties of a random access iterator (which is what std::sort() requires). That structure (or its member functions/operators) will need to both track which std::vector<int> (within the 2D vector) AND the particular int within that vector that it refers to. That will be moderately tricky (e.g. if the custom iterator refers to the last element of a particular std::vector<int>, incrementing it must give a result that references the first element of the next vector<int>). A std::vector<std::vector<int> > simply does not have any built in capability to give you such an iterator directly. I'll leave rolling such a custom iterator as an exercise.

Peter
  • 35,646
  • 4
  • 32
  • 74
0

Given that you know the order of iteration you can specify elements relative to the start.

vect.begin()     // first element
vect.begin() + 2 // third element

so if you want to sort only the first let's say 10 elements use the following:

std::sort(vect.begin(), vect.begin() + 10);

More here.

As others already mentioned you can not really sort a 2D vector. So either you sort each vector individually or flatten it to a 1D vector and use index calculations for 2D interpretation.

Seriously
  • 884
  • 1
  • 11
  • 25
  • So, how would I flatten the 2D vector into 1D and take it back to a 2D considering i want to prevent the column headers and row numbers not to be sorted. I've used the `sort(vect.begin() + 1, vect.end())` and it has prevented the column names from being sorted but still sorts the row numbers.
    Thank you
    – Daniel Wole Olamide Feb 13 '18 at 12:48
  • You do not want to switch data layout all the time. What I had in mind was e.g. if you have a NxN matrix you store it in a 1D vector `v` of size NxN. To access the element at position i/j you would use `v[i * N + j]`. If this does not fit what you had in mind maybe provide an example of the matrix you have and how you want it to be sorted. – Seriously Feb 13 '18 at 12:58
0
  1. Load your column you sort by into std::vector< std::pair > index; and set
    • the first element as row index in vector (0,1,2,...)
    • the second element will be value in the row and column
  2. Sort it by second item of the pair using this question: How do I sort a vector of pairs based on the second element of the pair?
  3. Now you have row index sorted by the column values in the vector < pair > and you can create new 2d vector and populate its rows using rows from the original 2d vector. In each iteration select row with index in original 2D vector using your first item in index vector.
nio
  • 5,141
  • 2
  • 24
  • 35