0

I've been search around Google but I didn't find what I need. I'm trying to create a vector that allows me to add 3 (and after I'll need to store 4) variables, access and sort them.

I'm implementing the vector as follows for 3 variables:

std::vector<std::pair<std::string, std::pair<int, double> > > chromosomes;

To add information (variables), I'm doing:

chromosomes.emplace_back(dirp->d_name, std::make_pair(WSA, fault_percent));

How can I access each parameter and sort them based on the WSA and fault coverage? As in a vector of pair that I can do that using members first and second.

And for 4 variables, it would be as follows?

std::vector<std::pair<std::string, std::string>, std::pair<int, double> > > chromosomes;

chromosomes.emplace_back( std::make_pair(dirp->d_name, x), std::make_pair(WSA, fault_percent));`
Biffen
  • 6,249
  • 6
  • 28
  • 36
Leonardo Alves
  • 37
  • 1
  • 10
  • 4
    It might be easier to use a [`std::tuple`](http://en.cppreference.com/w/cpp/utility/tuple) or just use a `struct` and you can name the members whatever you want. – NathanOliver Jan 25 '16 at 21:04
  • `std::vector, std::pair > >` shouldn't compile (and not just because of the extra `>`). – Biffen Jan 25 '16 at 21:07
  • Are you using pairs because that's the logically correct way to represent the relationship between the information? Or are you using pairs as a quick way to glue things together whether or not it makes sense? – David Schwartz Jan 25 '16 at 21:09
  • @NathanOliver isn't tuple of a fixed-size? I'm working with vectors because I need dynamic sizes. Maybe a struct can be what I need. Thank you – Leonardo Alves Jan 25 '16 at 21:11
  • @DavidSchwartz I'm using pairs because of the relationship between the information. Im reading a lot of files, and I'll get that three information from each file I am reading – Leonardo Alves Jan 25 '16 at 21:13
  • 3
    @LeonardoAlves A tuple has a fixed number of elements but you can have a vector of tuples. – NathanOliver Jan 25 '16 at 21:14
  • I've been struck by the hideous realization that you may believe that you can have a `vector` that starts out as a `vector>>` and later becomes a `vector, pair>>` **You cannot do this.** A `vector` is a templatized container that *only* holds elements of the type it is instantiated with. – Jonathan Mee Jan 26 '16 at 00:52

3 Answers3

3

As suggested here I think you should be using a vector of tuple<string, int, double>s or tuple<string, string, int, double>s respectively.

There is a defined tuple::operator< which uses the less-than-operator for each of it's composing types moving left to right. If a simple comparison of each element is sufficient then all you'll need to do is call sort:

sort(chromosomes.begin(), chromosomes.end());

If the tuple::operatior< does not provide a sufficient comparison for your needs sort provides an overload which takes a comparison lambda. Your lambda would need to do the following:

  1. Take in 2 const references to the tuples
  2. Return true if the first tuple is strictly smaller than the second tuple
  3. Return false if the first tuple is greater or equal to the second tuple

In the end your call would look something like this:

sort(chromosomes.begin(), chromosomes.end(), [](const auto& lhs, const auto& rhs) {
    // Your comparison between the two goes here
});

If you're not familiar with working with tuples you'll need to use the templated get method to extract either by index or type in the cases where there is not a duplicate type contained by the tuple.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
2

First to access to the different elements:

for (auto& x :chromosomes) 
    cout <<x.first<<": "<<x.second.first<<" "<<x.second.second<<endl; 

Next, to sort the elements on WSA:

sort(chromosomes.begin(), chromosomes.end(),
             [](auto &x, auto &y) { return x.second.first<y.second.first;});

If you want to sort on several criteria, for example WSA and fault_percent, you just have to change the lambda function for comparison:

sort(chromosomes.begin(), chromosomes.end(),
            [](auto &x, auto &y) { return x.second.first<y.second.first 
                          || (x.second.first==y.second.first 
                                 && x.second.second<y.second.second );});

Here is an online demo

Remark

Now what puzzles me, is why you want to use pairs of pairs or even tuples, when you could use a clean struct which would be easier to store/retrieve, and access its members:

struct Chromosome {
    string name; 
    int WSA; 
    double fault_percent;  
};   

vector <Chromosome> chromosomes;  

It would be much more readable and maintainable this way:

sort(chromosomes.begin(), chromosomes.end(),
            [](auto &x, auto &y) { return x.WSA<y.WSA 
                          || (x.WSA==y.WSA && x.fault_percent<y.fault_percent );});
     
Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • 1
    That what I was thinking, struct is less time processing too (I think). Thank you very much, and everyone that gave me a lot of good solutions. – Leonardo Alves Jan 25 '16 at 21:44
  • Firstly, `pair` and `tuple` have lexicographical comparison built-in, so the sort example would actually be `sort(cs.begin(), cs.end(), [](auto &x, auto &y) { return x.second < y.second; });`. Secondly, you really find `sort(cs.begin(), cs.end(), [](auto &x, auto &y) { return x.WSA < y.WSA || (x.WSA == y.WSA && x.fault_percent < y.fault_percent); });` more readable than `sort(cs.begin(), cs.end(), [](auto &x, auto &y) { return tie(x.WSA, x.fault_percent) < tie(y.WSA, y.fault_percent); });`? o_O I certainly do not! And, surprise surprise, the latter is implemented in terms of `tuple`. ;-] – ildjarn Jan 26 '16 at 03:55
  • I would further argue that any UDT that implements lexicographical comparison in terms of its members _without_ using `std::tie` is simply poor code, as the approach you've shown simply does not scale well as the number of members involved increases. – ildjarn Jan 26 '16 at 04:00
  • 1
    @ildjarn thank you for sharing on tuples. I have nothing against them and your remark about tie and lexicographic sort is certainly valid. My point is that it is not sound to construct a complex data structure solely on tuples. Your last example is readable because you could use member names of a clean struct, instead of refering to an ordinal unnamed tuple member. If later an additional info would be needed btw wsa and percentage, with tuples only OP would have to revise his full code, whereas with struct he ´d only need to review the part of codes where the additional element is relevant – Christophe Jan 26 '16 at 06:40
1

It seems like you need a table-like data structure, that allows sorting by multiple columns. C++ isn't the easiest language to manipulate table/matrix data structures in, but here's a few links to help you get started.

An example Table class: How to dynamically sort data by arbitrary column(s)

A vector/tuple solution, which is a slightly cleaner version of what you're currently working on: sorting table in place using stl sort

A lengthy discussion of this problem, which might give you some additional ideas: https://softwareengineering.stackexchange.com/questions/188130/what-is-the-best-way-to-store-a-table-in-c

Community
  • 1
  • 1
Francesca Nannizzi
  • 1,695
  • 13
  • 18