Results 1 to 16 of 16

Thread: Item position in QMap?

  1. #1
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Item position in QMap?

    Hi,

    I am currently using std::map to look up item position by key as (the key is either std::string or int, so it has operator==, operator>, and operator<):

    Qt Code:
    1. std::map::const_iterator it = map.find( key );
    2. if ( it != map.end() ) {
    3. return std::distance( map.begin(), it );
    4. }
    To copy to clipboard, switch view to plain text mode 

    I have 500,000 items in the map, and need to iterate through all 500,000 items and get each item's position. The loop takes 1 hours!!! So it is horribly wrong.

    Can someone give suggestion to speed it up, preferably still using std::map because the codes were like that originally, but if QMap can give much better performace, then I would have a reason to change to QMap...

    Thanks

  2. #2
    Join Date
    Jul 2008
    Location
    St. Louis, MO
    Posts
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Item position in QMap?

    My first guess is that you are iterating through most of the items.
    Hence, an index is required in order to avoid iterating through most items before finding what you need.
    I'm not real familiar with STL components that might do this. In Java there is TreeMap, which provides a red/black tree index to significantly reduce lookup times.
    A natural order is required for each object before such a tree will work.
    The help text for QMap indicates that it stores (key,value) pairs that provides a fast lookup based upon the key (i.e. via the find() iterator). In Qt this may be an option to consider in lieu of std::map. I assume that the key type must provide a natural ordering before the map lookup will work efficiently.

  3. #3
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Item position in QMap?

    Huh, I am not familiar with the internals of std::map but I suppose the results are similar to that of other map classes (such as QMap) i.e O(log(n)) lookup so something strikes me in your design : if I am not mistaken you are getting an iterator to an item using find() in a loop (which leads to O(n log(n)) asymptotic behavior

    I am not sure what you are trying to do but I suppose actually iterating over would be much better, e.g (pseudo code):
    Qt Code:
    1. int rank = 0;
    2. iterator it = container.begin();
    3. while ( it != container.end() )
    4. {
    5. doSomething(it.key(), it.value(), rank);
    6. ++it;
    7. ++rank;
    8. }
    To copy to clipboard, switch view to plain text mode 

    By the way, are you sure the map is the only bottleneck in your code? I have used QMaps with more than 100k items as well and iterating over the contents (and modifying them) never took more than a couple hundred of ms so one hour of map iteration looks very unrealistic to me, even with a very unoptimal lookup strategy.
    Last edited by fullmetalcoder; 14th March 2009 at 10:01.
    Current Qt projects : QCodeEdit, RotiDeCode

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Item position in QMap?

    Is using QHash (or an std:: equivalent) an option? It would drastically reduce lookup times.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Item position in QMap?

    I end up writing my own binary search function. My array is in increasing order, I just need the position of an item in the array....Not sure how to use QHash...

    I was misled by QList::indexOf, which uses sequentially search and is killing me...

    Qt Code:
    1. template <typename Type>
    2. int indexOf( const QList<Type>& lists, const Type& value, int pos_from, int pos_to )
    3. {
    4. if ( pos_to < pos_from ) {
    5. return -1; // not found
    6. }
    7.  
    8. int mid = pos_from + ( ( pos_to - pos_from ) / 2 );
    9. if ( lists[ mid ] > value ) {
    10. return indexOf( lists, value, pos_from, mid - 1 );
    11. } else if ( lists[ mid ] < value ) {
    12. return indexOf( lists, value, mid+1, pos_to );
    13. } else {
    14. return mid; // found
    15. }
    16. }
    To copy to clipboard, switch view to plain text mode 

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Item position in QMap?

    Quote Originally Posted by lni View Post
    I end up writing my own binary search function.
    I'm sure you do realize Qt already has one, right?

    My array is in increasing order, I just need the position of an item in the array....
    So... why are you using a map?

    Not sure how to use QHash...
    It's like QMap but with logarithmic complexity instead of QMap's linear when dealing with lookups and inserts. It doesn't guarantee the key order though.

    Qt Code:
    1. template <typename Type>
    2. int indexOf( const QList<Type>& lists, const Type& value, int pos_from, int pos_to )
    3. {
    4. if ( pos_to < pos_from ) {
    5. return -1; // not found
    6. }
    7.  
    8. int mid = pos_from + ( ( pos_to - pos_from ) / 2 );
    9. if ( lists[ mid ] > value ) {
    10. return indexOf( lists, value, pos_from, mid - 1 );
    11. } else if ( lists[ mid ] < value ) {
    12. return indexOf( lists, value, mid+1, pos_to );
    13. } else {
    14. return mid; // found
    15. }
    16. }
    To copy to clipboard, switch view to plain text mode 
    Hooray! We're reinventing the wheel again!

    How about:
    Qt Code:
    1. QList<Type>::const_iterator it = qBinaryFind(lists, value);
    To copy to clipboard, switch view to plain text mode 
    ?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. #7
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Item position in QMap?

    Quote Originally Posted by wysota View Post
    It's like QMap but with logarithmic complexity instead of QMap's linear when dealing with lookups and inserts. It doesn't guarantee the key order though.
    Just for the sake of correctness : QHash offers (amortized) O(1) lookups whereas QMap offer O(log(n)) lookups. This comes from the fact that the data is sorted by key (ascending order) in a QMap and searching is done via binary search whereas data is unsorted in a QHash but associated to an internal key computed from the actual key using a hashing function. The "amortized" means that O(1) will only be obtained if the has function is O(1) itself and if the hashing function associate (as much as possible) different hash to different keys.

    The docs explain that (though they of course do not cover the theory of algorithmic complexity...)
    Current Qt projects : QCodeEdit, RotiDeCode

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Item position in QMap?

    For sake of completeness here is something to read as well:
    http://doc.trolltech.com/qq/qq19-containers.html
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Item position in QMap?

    Quote Originally Posted by wysota View Post
    Qt Code:
    1. QList<Type>::const_iterator it = qBinaryFind(lists, value);
    To copy to clipboard, switch view to plain text mode 
    Wow!!! There is a qBinaryFind in Qt already!!! Thanks for the hint!! Qt has grown so big, it is good and bad

  10. #10
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Item position in QMap?

    Quote Originally Posted by lni View Post
    Wow!!! There is a qBinaryFind in Qt already!!! Thanks for the hint!! Qt has grown so big, it is good and bad
    Wait a sec, I need the index of the item in the container, not the iterator...

    QStringList list;
    list << "one" << "two" << "three";

    I need
    int indexOf( list, "two" )

    which return 1 in this example.

  11. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Item position in QMap?

    Quote Originally Posted by lni View Post
    Wow!!! There is a qBinaryFind in Qt already!!! Thanks for the hint!! Qt has grown so big, it is good and bad
    It's been there for ages.

    Quote Originally Posted by lni View Post
    Wait a sec, I need the index of the item in the container, not the iterator...
    Qt Code:
    1. QList<...>::const_iterator it = qBinaryFind(container, ...);
    2. int index = (it==container.end()) ? -1 : it-container.begin();
    To copy to clipboard, switch view to plain text mode 
    Last edited by wysota; 15th March 2009 at 17:00.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  12. #12
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Item position in QMap?

    Quote Originally Posted by wysota View Post
    Qt Code:
    1. QList<...>::const_iterator it = qBinaryFind(container, ...);
    2. int index = (it==container.end()) ? -1 : it-container.begin();
    To copy to clipboard, switch view to plain text mode 
    That is exactly what I did using stl
    Qt Code:
    1. std::map::const_iterator it = map.find( key );
    2. if ( it != map.end() ) {
    3. return std::distance( map.begin(), it );
    4. }
    5.  
    6. return -1;
    To copy to clipboard, switch view to plain text mode 

    This code took 1 hour to run through a container that contains 500,000 items. Unless "it - container.begin()" is different from std::distance( ... ).

  13. #13
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Item position in QMap?

    This is weird, could it be stl bug in std::distance?

    I compare stl and Qt container, when totalItems is more than a certain number, say 10000, the stl becomes extremely slow but QList is fine...

    Qt Code:
    1. #include <QList>
    2. #include <set>
    3. #include <iostream>
    4. #include <math.h>
    5.  
    6. static int findIndex( const std::set<int>& stlSet, int value )
    7. {
    8. std::set<int>::const_iterator it = stlSet.find( value );
    9. if ( it != stlSet.end() ) {
    10. return std::distance( stlSet.begin(), it );
    11. }
    12.  
    13. return -1;
    14. }
    15.  
    16. static void testStl( int totalItems )
    17. {
    18. std::set<int> stlSet;
    19.  
    20. for ( int idx = 0; idx < totalItems; idx++ ) {
    21. stlSet.insert( idx );
    22. }
    23.  
    24. for ( int idx = 0; idx < totalItems; idx++ ) {
    25. //std::cout << findIndex( stlSet, idx ) << std::endl;
    26. findIndex( stlSet, idx );
    27. }
    28.  
    29. }
    30.  
    31. static int findIndex( const QList<int>& qlists, int value )
    32. {
    33. QList<int>::const_iterator it = qBinaryFind( qlists, value );
    34. if ( it != qlists.end() ) {
    35. return it - qlists.begin();
    36. }
    37.  
    38. return -1;
    39. }
    40.  
    41. static void testQList( int totalItems )
    42. {
    43. QList<int> qlists;
    44.  
    45. for ( int idx = 0; idx < totalItems; idx++ ) {
    46. qlists << idx;
    47. }
    48.  
    49. for ( int idx = 0; idx < totalItems; idx++ ) {
    50. //std::cout << findIndex( qlists, idx ) << std::endl;
    51. findIndex( qlists, idx );
    52. }
    53.  
    54. }
    55.  
    56. int main( int argc, char** argv )
    57. {
    58. int totalItems = atoi( argv[1] );
    59.  
    60. std::cout << "Start testQList" << std::endl;
    61. testQList( totalItems );
    62. std::cout << "End testQList\n" << std::endl;
    63.  
    64. std::cout << "Start testStl" << std::endl;
    65. testStl( totalItems );
    66. std::cout << "End testStl" << std::endl;
    67.  
    68. }
    To copy to clipboard, switch view to plain text mode 

  14. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Item position in QMap?

    Qt containers are in general much faster than their stl counterparts. std::map has linear lookup complexity as far as I remember so you need to do up to 500000 comparisons to find an item in it. It's simply not scalable. Use a hash array of some sort (like QHash) instead. Maybe you should tell us what you are holding in the map and why you need to find the index of some item there? Maybe we can suggest a better solution then...
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  15. #15
    Join Date
    Dec 2006
    Posts
    426
    Thanks
    8
    Thanked 18 Times in 17 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Item position in QMap?

    Quote Originally Posted by wysota View Post
    Qt containers are in general much faster than their stl counterparts. std::map has linear lookup complexity as far as I remember so you need to do up to 500000 comparisons to find an item in it. It's simply not scalable. Use a hash array of some sort (like QHash) instead. Maybe you should tell us what you are holding in the map and why you need to find the index of some item there? Maybe we can suggest a better solution then...
    I have an array of pointers, each having an unique key (type of std::string and int). So I made a map to hold them (std::map<std::string, MyClass*>, and std::map<int, MyOtherClass*>).

    I use std::map because it is sorted and is fast to look them up by the key. Now, I have a key and I want to find the location (or index) of the item within the container.

    std::map<..>::const_iterator it = map.find( key ) is fast as expected, but I need to convert the iterator to its position inside the container, which I used std::distance( map.begin(), it ), and it is extremely slow (take hours to look up 500,000 items)...

  16. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Item position in QMap?

    Quote Originally Posted by lni View Post
    I use std::map because it is sorted and is fast to look them up by the key.
    Consider the fact that there are different sort orders than just alphabetical. There are faster solutions than this, QHash is one of them.

    Now, I have a key and I want to find the location (or index) of the item within the container.
    Ok, but why? What do you intend to do with it?

    std::map<..>::const_iterator it = map.find( key ) is fast as expected, but I need to convert the iterator to its position inside the container, which I used std::distance( map.begin(), it ), and it is extremely slow (take hours to look up 500,000 items)...
    I'm not sure what std::distance() does, but you should be able to substract iterators to receive an index. In some cases, like vectors this should be instantaneous. Maybe you should switch to a sorted vector? Use lower_bound (or qLowerBound) to insert items in the vector and abuse the fact that vectors stores data in adjacent memory cells - the index of the item is a difference of pointers representing both items divided by the size of the pointer - this is O(1) op.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. View, Scene, Item and thread??
    By dungsivn in forum Qt Programming
    Replies: 5
    Last Post: 20th August 2008, 19:21
  2. position of an item in a QStringList
    By jaca in forum Newbie
    Replies: 4
    Last Post: 29th May 2008, 05:49
  3. Item Delegate Painting
    By stevey in forum Qt Programming
    Replies: 3
    Last Post: 9th May 2008, 07:37
  4. How to get a position of the menu bar item?
    By Mad Max in forum Qt Programming
    Replies: 2
    Last Post: 20th November 2006, 03:20
  5. how change the QListBox item position by pixel
    By roy_skyx in forum Qt Programming
    Replies: 2
    Last Post: 20th January 2006, 01:34

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.