Использование нескольких ключей с map / unordered_map (многомерный)

0

У консьержа есть несколько ведер (vector<float>). Мне нужно получить доступ к этим ковшим на основе некоторых индексов. Пример:

int indexX, indexY, indexZ, indexW;

Поэтому, когда приходит новый пункт, мне нужно поставить точку в правильные ведра. Теперь я делаю что-то вроде этого:

//            X                  Y                  Z                  W   => Bucket
unordered_map<int, unordered_map<int, unordered_map<int, unordered_map<int, vector<float>>>>> indexedTable;

// New point arrives and I put it in the right bucket:
indexedTable[indexX][indexY][indexZ][indexW].push_back(myValue);

Но я нахожу это очень уродливым, и, к сожалению, это тоже очень медленно. Например, для доступа к ней за 1700 пунктов требуется 0,56 с, что слишком медленно.

Есть ли лучшие/более быстрые альтернативы, без использования Boost?
Обратите внимание, что эта структура данных в моих потребностях сопоставима с разреженной матрицей (многомерная), потому что очень мало "ведер" будут заполнены чем-то.

Теги:
hashmap
map

2 ответа

3
Лучший ответ

Вместо использования этого 4-глубинного монстра вы можете просто использовать unordered_map со struct содержащей 4 индекса в качестве ключа, и vector<float> в качестве типа значения. Предоставьте функции сравнения и хеш-функции для структуры, и вы находитесь в бизнесе.

struct indices
{
    int indexX, indexY, indexZ, indexW;

    bool operator==(indices const& other) const
    {
        return std::tie(indexX, indexY, indexZ, indexW) ==
               std::tie(other.indexX, other.indexY, other.indexZ, other.indexW);
    }
};

struct indices_hash
{
    std::size_t operator()(indices const& i) const
    {
        std::size_t seed = 0;
        boost::hash_combine(seed, i.indexX);
        boost::hash_combine(seed, i.indexY);
        boost::hash_combine(seed, i.indexZ);
        boost::hash_combine(seed, i.indexW);

        return seed;
    }
};

std::unordered_map<indices, std::vector<float>, indices_hash> m;

Поскольку вы не хотите использовать Boost, либо hash_combine альтернативу hash_combine либо скопируйте реализацию здесь.

Живой пример

  • 0
    Я бы включил конструктор для indices который принимает все 4 параметра, и я бы предоставил специализацию для std::hash<indices> чтобы вам не приходилось явно называть хэш в unordered_map .
  • 0
    @Praetorian: я скопирую оттуда hash_combine, но как насчет функции hash_value () ? seed ^= **hash_value(v)** + 0x9e3779b9 + (seed << 6) + (seed >> 2);
Показать ещё 2 комментария
2

Пока вам не нужно обращаться ко всем точкам измерения (т.е. Ко всем ведрам, где y == 2), тогда вам следует рассмотреть возможность использования единой структуры для представления вашей точки, а не для вложенных карт.

Что-то в этом роде:

struct Point_t
{
    int x;
    int y;
    int z;
    int w;
    Point_t (int _x, int _y, int _z, int _w) : x (_x), y (_y), z (_z), w (_w) {}
};

// Make sure the points are sortable
struct CmpPoint_t
{
    bool operator() (const Point_t& lhs, const Point_t& rhs)
    {
        return (lhs.x < rhs.x &&
                lhs.y < rhs.y &&
                lhs.z < rhs.z &&
                lhs.w < rhs.w);
    }
 };

typedef std::vector<float> Bucket_t;
typedef std::map<Point_t, Bucket_t, CmpPoint_t> BucketMap_t;

Применяя пример использования:

BucketMap_t indexedTable;
indexedTable[Point_t(indexX, indexY, indexZ, indexW)].push_back (myValue);
  • 0
    очень хорошее решение. Но зачем мне эта функция сравнения? Если я использую unordered_map, мне не нужно их сортировать ...? Я считаю, что вам нужен только оператор ==, такой как @Pretorian
  • 1
    На карте должен быть operator< для ваших ключей, чтобы их можно было отсортировать. Для unordered_map вы должны предоставить реализацию operator== а также хеш-функцию. С unordered_map качество хеш-функции влияет на производительность.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню