[SOLVED]Behaviour of QMultiMap



  • Hi everyone,

    I was always under the impression that QMultiMap would behave like this:

    If i insert 3 ValuePairs {(1,one),(2,two),(2,zwei)} the QMultiMap would look like this
    @
    1 | 2
    one | two
    | zwei
    @
    but now during debugging I get the feeling it does this
    @
    1 | 2 | 2
    one | two | zwei
    | zwei | two
    @
    I iterate over the map like this

    @QList<int> result;

    QMultiMap<QString, int>::const_iterator it = sortedMultiMap.constBegin();
    while(it != sortedMultiMap.constEnd())
    {
    QList<int> values = sortedMultiMap.values(it.key());
    for(int i = 0; i < values.size(); ++i)
    {
    result.append(values.at(i);
    }
    ++it;
    }@

    Can anyone plz provide some insight. I'm just using the QMultiMap to sort some pointers to objects with regard to their timestamp. At some point I want to put them in a QList with the oldest timestamp (the smallest timestamp) first.


  • Moderators

    Well, QMultiMap does only sorting the "key" (your '1', '2') not the value. It supposed to do it this way. It is the same stl multimap.
    You need to define it differently for what you are looking for.



  • The iterator you use iterates over all key/value pairs you inserted into the map. If you inserted a key twice, then you get an iterator with that key twice. Then, inside your loop, you request all values for a specific key again. That means that you will find the same values more than one time in your case. The order in which these values are returned is not defined.

    If you want all values if your map, you should just use QMap::values(). If you want to iterate over all key/value pairs, then use both the key() and the value() method of the iterator to get to your items.



  • Thanks for your quick responses.

    I think my problem is that my QMultiMap can not sort the keys correctly if they're of the type QDateTime.
    Although QDateTime provides the neccessary < operator.
    If I just iterate like this
    @
    QList<somePointer*> result;

    QMultiMap<QDateTime, somePointer*>::const_iterator it = sortedMultiMap.constBegin();
    while(it != sortedMultiMap.constEnd())
    {
    result.append(it.value());
    ++it;
    }
    @
    I only get three values which is what I want but they are inserted in the wrong order.
    In my app I get this for example: (05:59 | somePointer1) ; (06:44 | somePointer2) ; (06:00 | somePointer3) in that exact order (which is the order they were inserted in the QMultiMap); when I really want this: (05:59 | somePointer1); (06:00 | somePointer3) ; (06:44 | somePointer2) .

    So how can I iterate over my keys in the correct order and not get values twice or more?

    I already checked my QList before inserting but the problem regarding the order still remains
    @
    QList<somePointer*> result;

    QMultiMap<QDateTime, somePointer*>::const_iterator it = sortedMultiMap.constBegin();
    while(it != sortedMultiMap.constEnd())
    {
    QList<somePointer*> values = sortedMultiMap.values(it.key());
    for(int i = 0; i < values.size(); ++i)
    {
    if(!result.contains(values.at(i)))
    {
    result.append(values.at(i));
    }
    }
    ++it;
    }
    @



  • Weird, I thought QMap would keep it sorted property. Just to be sure, those QDateTimes do have the same date, right?

    If QDateTimes are not properly sorted, then that would qualify as a bug. As a workaround in that case, you could:

    first retreive the used keys using the keys() method, then

    sort the list of keys (qSort should do), then

    iterate over the list of keys, and

    for each key, retreive the list of values (which will not be sorted, of course)

    But if you really need such a workaround, be sure to file a bug report agains QMap in "Jira":http://bugreports.qt.nokia.com as well!



  • I could of course just use stl::list insert all keys then sort the list and iterate over the MultiMap using the sorted keys, but thats kind of inefficient isn't it ^^.



  • HiHi

    had the same idea :-P

    @Andre: Yes they're all of the same date only the time varries. And even if they had different dates shouldn't that be handled correctly by QDateTime's < operator ?



  • [quote author="KA51O" date="1311675772"]I could of course just use stl::list insert all keys then sort the list and iterate over the MultiMap using the sorted keys, but thats kind of inefficient isn't it ^^.[/quote]
    Sure it is inefficient, that's why I called it a workaround and qualified the situation as bug if it were truly needed.



  • @Andre I wrote that before you posted the exact same idea. I didn't mean to criticise your answer.



  • No, that' s ok. If the dates are all the same, and the times are then sorted like you showed, then there is a bug. The point was, that if the dates would have been different, the sorting you showed us (only showing the times) could have been correct. Of course the sorting should be correct even if the dates are different.

    Please prepare a small, self-contained example that displays the faulty behaviour, and attach that to your bug report.



  • Ok I wrote a small test case and in that test case the behaviour is correct (code below)

    @
    QMultiMap<QDateTime,int> timeSortedIntegers;
    timeSortedIntegers.insert(QDateTime::currentDateTime().addSecs(-120),1);
    timeSortedIntegers.insert(QDateTime::currentDateTime(),2);
    timeSortedIntegers.insert(QDateTime::currentDateTime().addSecs(-60),3);

    QList<int> testList1;
    QMultiMap<QDateTime,int>::const_iterator it1 = timeSortedIntegers.constBegin();
    while(it1 != timeSortedIntegers.constEnd())
    {
    testList1.append(it1.value());
    ++it1;
    }

    QList<int> testList2;
    QMultiMap<QDateTime,int>::const_iterator it2 = timeSortedIntegers.constBegin();
    while(it2 != timeSortedIntegers.constEnd())
    {
    QList<int> values = timeSortedIntegers.values(it2.key());
    for(int i = 0; i < values.size(); ++i)
    {
    if(!testList2.contains(values.at(i)))
    {
    testList2.append(it2.value());
    }
    }
    ++it2;
    }

    for(int j = 0; j < testList1.size(); ++j)
    {
    int testInt1 = testList1.at(j);
    int test1 = testInt1;
    }

    for(int k = 0; k < testList1.size(); ++k)
    {
    int testInt2 = testList2.at(k);
    int test2 = testInt2;
    }
    @

    So I must be doing something stupid in my code.

    I'll keep you posted.



  • I got it.

    One of the QDateTime's I used was in UTC format and all the others in localTime format.
    The result was actually correct if all QDateTime's were converted to the same type.

    Curses!!!!



  • Ah! Great that you managed to solve it. It seemed an unlikely bug to be in QMap or QDateTime (something that would have been caught by a unit test), but you never know... Qt is not perfect. But, in this case, it was pilot error after all :-) An easy mistake to make, and a hard to spot one. I am glad you managed to fix it!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.