0

How can I store four parameters with a value in c++ and be able to recall it.

For example I have parameters u , k , i , childEdge and a value called val.

I want to store them like this: (5,4,6,1) = 42.

And be able to access them with something like this : int answer = find(5,4,6,1 ) so answer would be 42

I was using a 4D array, but for large inputs it doesn't seem to work well in c++

  • 3
    Consider [`std::unordered_map`](https://en.cppreference.com/w/cpp/container/unordered_map). O(1) lookup and only needing as much place as you have inputs. – n314159 Jan 08 '20 at 14:02
  • "*for large inputs it doesn't seem to work well*" How large inputs are we talking about? – Yksisarvinen Jan 08 '20 at 14:04
  • @n314159 Well, `std::unordered_map` needs a significant amount of additional space. If the five value are 32 bit integers and you compile on a 64 bit architecture, it will have almost 100% space overhead (because the standard essentially requires open addressing, i.e. buckets forming some linked list or tree) before even considering the overhead of separate allocations for each bucket. – Max Langhof Jan 08 '20 at 14:23
  • Yes, but your space only depends linearly on ths size of your input. It does not depend in the size of your variables as it does with a 4D vector. – n314159 Jan 08 '20 at 14:29

6 Answers6

4

So what you want is a map from four parameters to one value. You can use either std::map or std::unordered_map depending on your needs1. The main question is how to express the four-value key. Here are some options:

  • using MyKey = std::tuple<int, int, int, int>;

  • using MyKey = std::array<int, 4>;

  • struct Parameters { int u, k, i, childEdge; };
    using MyKey = Parameters;

Your data structure would then be std::map<MyKey, int> or std::unordered_map<MyKey, int>.

I would prefer the struct option, as it is the clearest. However, you will have to provide operator< for std::map or std::hash and operator== for std::unordered_map to work with it (or equivalently, using such functors as additional template arguments for the maps). Research "custom key std::map" or similar to learn more, see here or here.

1 There are other options, such as a sorted std::vector, which may or may not outperform the associative containers, depending on your usage patterns. But that's going off topic here.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • Thank you. But how would I call this or add values to it. I did something like this (After initializing the struct and the unordered map) : unordered_map glob; . I call values like this: if (!glob[(u,k,i,childEdge)]==0) and add values like this glob[(u,k,i,childEdge)]=get<0>(best); but it produces many errors –  Jan 08 '20 at 14:18
  • You can't use `(u, k, i, childEdge)`. C++ is not Python, this is simply not the right syntax. You can use `glob[{u, k, i, childEdge}]` though (curly braces instead of parentheses), which automatically constructs the `MyKey` from those four parameters. – Max Langhof Jan 08 '20 at 14:28
  • @thriteenchess Also, the only one which will work out-of-the-box is `std::map` with either the `std::tuple` or the `std::array` (because those already have `operator<` provided). If you want to use `std::unordered_map` you must specify a way to hash and equality-compare `MyKey`. – Max Langhof Jan 08 '20 at 14:35
2

You could use a std::map. I believe you can then use map.find to get your value.

Kevin Lewis
  • 21
  • 1
  • 3
1

Use std::array as a key. You'll have to provide your own hash function:

#include <array>
#include <boost/functional/hash.hpp>
#include <functional>
#include <iostream>
#include <unordered_map>

namespace std {
template <typename T, size_t sz>
struct hash<array<T, sz>> {
  [[nodiscard]] size_t operator()(array<T, sz> const& arr) const noexcept {
    return ::boost::hash_range(arr.cbegin(), arr.cend());
  }
};
}  // namespace std

int main() {
  std::unordered_map<std::array<int, 4>, int> m;
  m[{5, 4, 6, 1}] = 42;
  m[{1, 2, 3, 4}] = 1234;
  m[{2, 2, 2, 2}] = 2222;

  std::cout << m[{5, 4, 6, 1}] << '\n';
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
0

You can use a map, in the key 5, 4, 6 and 1 the value will be 42. Then a search function receiving the parameters and searching them in the map.

Raí Borges
  • 71
  • 1
  • 5
0

How can I store four parameters with a value

Write a class:

struct Key {
    int  u, k, i, childEdge;
};

Objects of type Key will store the four parameters in one.

And be able to access them with something like this : int answer = find(5,4,6,1 )

You can associate a value with another by storing it in an associative container. Specifically to map a value to another, you can use a(n unordered) map. There are containers for that in the standard library. You can use the class described above as a key to the map to implement the described operation efficiently.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

How about a map of a tuple and an int e.g. std:map<std::tuple<int, int, int, int>&, int>. This way you will be able to use the tuple directly as the key as it is stored as a reference.

However, I would suggest a completely different approach than using a tuple. Why not create a class only for all the 5 items. And then have a list of those objects or an std::unordered_map if you want better accessibility to those data.

Sisir
  • 4,584
  • 4
  • 26
  • 37
  • Did you mean `std::unordered_set` for the last one? – Max Langhof Jan 08 '20 at 14:13
  • Well, depending on OP's need, he/she can use an `std::unordered_set` if can't have a key-value pair or `std::unordered_map` if O(1) element access is needed – Sisir Jan 08 '20 at 14:18