Question

I have this set of data:

[ step:-1, name:"BaseName1",  value:v1 ]
[ step:-1, name:"BaseName2",  value:v2 ]
[ step:2,  name:"ParamName3", value:v3 ]
[ step:2,  name:"ParamName4", value:v4 ]
[ step:0,  name:"ParamName5", value:v5 ]
[ step:0,  name:"ParamName6", value:v6 ]
[ step:1,  name:"ParamName7", value:v7 ]
[ step:1,  name:"ParamName8", value:v8 ]

That I would like to convert to a QVariant, like this:

[
    "BaseName1": v1,
    "BaseName2": v2,
    "steps": [{
            "ParamName5": v5,
            "ParamName6": v6
        }, {
            "ParamName7": v7,
            "ParamName8": v8
        }, {
            "ParamName3": v3,
            "ParamName4": v4
        }
    ]
]

I figured it should be like this:

QVariantMap params;
params["Base_param_1"] = value;
params["Base_param_2"] = value2;
params["steps"] = QVariantList();

But for the array, I need the data to be ordered; which means I should insert step 0 in the params["steps"] before steps 1 and 3 (and step 2 should be empty).
Also, sorting the input data is not an option.

I tried to implement this with the following code:

struct Params{ 
    QString name;  
    QVariant value; 
    int step;/* -1 for base param */ 
};
QList<Params> _params = (...);

QVariantMap v_settings;
QVariantList v_steps;

for(int i=0; i<_params.size(); i++){
    const Param &param = _params[i];

    if( param.index == -1 ){
        v_settings.insert(param.name, param.value);
    }
    else {
        // if list too small, append empties to the list until it exists
        while( v_steps.size() < param.index ){
            QVariantMap map;
            v_steps.append(map);
        }

        v_steps.at(param.index).toMap().insert(param.name, param.value);
    }
}
v_settings.insert("steps", v_steps);

But the code fails at some point with an index out of bounds when encountering this line:

v_steps.at(param.index).toMap().insert(param.name, param.value);

So I guess my "fill with empty maps" loop failed somehow. How should I do here?

Was it helpful?

Solution

There are several issues in your code.

"Index is out of bounds" issue happens because you didn't add enough objects to your list. You should write

while( v_steps.size() <= param.index ) {

i.e. replace < with <=. It will ensure that, e.g. 6 elements will be contained in the array before you access the 5th element (elements count from 0, remember?)

Another issue is in toMap().insert. toMap() returns QMap by value, not by reference. So there is no point in calling insert on it because it's just temporary value that has not been assigned to any variable. It will be destroyed immediately after insert ends, and no changes will be stored.

I suggest you to use QVector<QVariantMap> v_steps to store your data. QVector is better than QList in this case because it's easy to resize() it. Inserting can be done using the following code:

v_steps[param.index].insert(param.name, param.value);

Then you need to convert it to QVariantList:

QVariantList v_steps_real;
foreach(QVariantMap map, v_steps) {
  v_steps_real << map;
}
v_settings.insert("steps", v_steps_real);

Note that you can use [] operator instead of insert() to insert values into a map:

map["key"] = value;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top