Tomáš Zato
Tomáš Zato

Reputation: 53119

Get item at specific offset of QMap

I have a QMap that represents a database row. The items are indexed by column name:

QMap<QString, QVariant> mapOfItems_;

I then have a method to retrieve item by columnn name:

QVariant ImportDataSourceRow::byName( const QString& name )
{
    if(mapOfItems_.contains(name))
      return mapOfItems_.value(name);
    else
      throw NoSuchColumn();
}

I would like to also implement method to get item by column index (0 for first column):

QVariant ImportDataSourceRow::byIndex( size_t index )
{
    // Now what?
}

How can I get the value at offset index from the map? Is QMap even guaranteed to be ordered as I need it to be?

Upvotes: 3

Views: 6197

Answers (3)

techwinder
techwinder

Reputation: 11

Not recommended, but you can try to do it this way:

QList<QString> list = mapOfItems_.values();
if(index>=0 && index<list.count()) return list.at(index);
return QString();

Don't know how it works with a QVariant though.

Upvotes: 0

Drop
Drop

Reputation: 13005

Associative (dictionary-like) containers such as QMap and std::map rarely provide sequential indexing as internally they are typically implemented as tree-like data structures (for example, Red-Black Tree).

Notable exception is boost's flat_map. It is implemented as a pair of contiguous arrays, where mapping of the key and value is expressed with array indices: mapped key and value have the same index. flat_map provides method nth() to access value by index:

boost::container::flat_map<std::string, float> geek_numbers;
geek_numbers.emplace("pi", 3.14f);
geek_numbers.emplace("e", 2.72f);
geek_numbers.emplace(
    "Answer to the Ultimate Question of Life, The Universe, and "
    "Everything",
    42.0f);
auto 0th = geek_numbers.nth(0); // 42.0f
auto 1st = geek_numbers.nth(1); // 2.72f
auto 2nd = geek_numbers.nth(2); // 3.14f

flat_map "emulates" interface and behavior of the std::map and sorts elements by key. You can use custom predicates.

Note that standard containers are suitable only for simplest database-like usecases. In general, databases is a very complicated topic. There are entire theories being built about it. If your dataset is large and you need to perform complicated indexing and queries, think about embedding one of the database engines available (e.g. SQLite, or other, more heavyweight ones).

Upvotes: 2

Frank Osterfeld
Frank Osterfeld

Reputation: 25155

The entries of a QMap are guaranteed to be ordered by key, in your case that'd be QString::operator<.

To get the position inside the map, you can use:

const auto it = mapOfItems.find(name);
const auto index = std::distance(mapOfItems.begin(), it);

Note that your byName() method would be more efficient if you used constFind() and throw if the returned iterator equals mapOfItems.constEnd(), instead of doing two lookups (contains and value()).

Upvotes: 2

Related Questions