0

I have the following three-level data structure (bottom to top):

  1. object C: {string, T, float} (where T is also an object)

  2. sorted container B of objects C with same string by highest float first

  3. sorted container A of objects B by lowest max(C.float) (i.e. B[0]) first

So at the beginning I'll have a bunch of C with pre-computed float values and my data structure should look like this:

A:
    B:
        C:
            string: "one"
            T: {object}
            float: 10
        C:
            string: "one"
            T: {object} # different from the above of course
            float: 8.3
        C:
            string: "one"
            T: {object}
            float: -4
    B:
        C:
            string: "two"
            T: {object}
            float: 15
        C:
            string: "two"
            T: {object}
            float: 2
        C:
            string: "two"
            T: {object}
            float: 0

No difficult problem up to now, as I could just simply put all of this into a set of sets (/multisets) and be done with it. Here is where it get's difficult: I will have to extract a subset of these to compute a solution of my problem (the first C of every B). If there is no solution, then remove the topmost C and extract the new subset to try again. In python pseudo-code:

def get_list():
    c_list = []
    for b in A:
        c_list.append(b[0]) # element in B with highest float value
    return c_list

def solve():
    for i in range(1, 3): # three tries
        c_list = get_list()
        # do stuff with c_list
        if fail:
            del A[0][0] # the topmost C element in the first B
            continue

But when I delete this A[0][0] (i.e. the C with {"one", T, 10}), I need the whole thing to re-sort itself. Therefore I can't use sets as I'd be modifying A[0], which a STL set/multiset doesn't allow.

The other solution would be to create classes, define the operator() or operator< for each of the two levels I need to do a comparison on (B and C) for std::sort() and stuff everything into a two-level STL vector. However this just seems overly complicated/my non-professional C++ intuition tells the there should be an easier way to code this neatly.

Performance is important as it's a "real-time" application for a robot, but not of topmost priority as I'll only have say up to 30 C.

Pronex
  • 274
  • 3
  • 14

2 Answers2

0

It seems that you are indexing by position, rather than value. The simplest data structure to use when you don't need efficient lookup by key is std::vector. I believe that would address your problems.

The std::set container is an ordered set of values.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • So the question concerning `std::vector` (cf. second to last paragraph in question) was if there is no other way around defining `operator<` for every step of the data structure. You're saying this is the best solution nevertheless? – Pronex Dec 02 '17 at 23:03
  • @Pronex: To be honest, the question is unclear. I am not sure what you really want. Do you want to index by two level keys and then keep a list of values? Then use map/unordered_map for the outer levels and a vector internally. If the contents of the vector affect the ordering then every operation you do can affect that and you will be better off managing it manually (I doubt this is the case, but if you have to, do it) – David Rodríguez - dribeas Dec 03 '17 at 21:44
  • @dribeas I don't need a two-level index as I only ever want to extract the first element of every sub-list (i.e. `c_list[0][0]`, `c_list[1][0]`, etc.). But your second interpretation is right: every modification/deletion does affect the ordering. So yeah, it seems like I will need to do it manually as you suggested. – Pronex Dec 04 '17 at 00:09
0

Following David's suggestion to use std::vector nevertheless and this post, the simplest solution seems to be using the std::sort with a lambda expression. That way one doesn't need to define any additional classes (like B in this case) or any operator overloads.

class C {
    string type;
    T obj;
    float sat;
};

And then:

vector<vector<C>> c_list = getData();
// Sort Bs
auto b_sort = [] (const C& lhs, const C& rhs) { return lhs.sat > rhs.sat; };
for (auto&& b : c_set) {
    sort(b.begin(), b.end(), b_sort);
}
// Sort A
sort(c_set.begin(), c_set.end(),
    [] (const vector<C>& lhs, const vector<C>& rhs) { return lhs[0].sat < rhs[0].sat; });

The main caveat in this solution is that the container is not inherently sorted when a C is removed. So the sorting above has to be called manually.

Pronex
  • 274
  • 3
  • 14
  • 1
    Removals from the vector will not affect the order of the objects already stored. It will still be sorted. Insertions are more complicated, but removals should be trivial – David Rodríguez - dribeas Dec 04 '17 at 09:49