roland rabien
tengo un std::map
que estoy usando para almacenar valores para las coordenadas x e y. Mis datos son muy escasos, por lo que no quiero usar matrices o vectores, lo que resultaría en una pérdida masiva de memoria. Mis datos oscilan entre -250000 y 250000, pero solo tendré unos pocos miles de puntos como máximo.
Actualmente estoy creando un std::string
con las dos coordenadas (es decir "12x45"
) y usarlo como clave. Esta no parece la mejor manera de hacerlo.
Mis otros pensamientos fueron usar un int64 y meter los dos int32 en él y usarlo como clave.
O para usar una clase con las dos coordenadas. ¿Cuáles son los requisitos de una clase que se utilizará como clave?
¿Cuál es la mejor manera de hacer esto? Prefiero no usar un mapa de mapas.
Utilice std::pair
std::map<std::pair<int,int>, int> myMap;
myMap[std::make_pair(10,20)] = 25;
std::cout << myMap[std::make_pair(10,20)] << std::endl;
-
un par funciona pero es genérico. Podría ser una buena idea definir un tipo personalizado que exprese lo que realmente significa el par, coordenadas cartesianas o lo que sea.
– bames53
10 de julio de 2013 a las 17:20
-
@ bames53 El principal problema con eso es que luego debe implementar un operador de comparación para el nuevo tipo, lo que puede no tener sentido si todo lo que desea garantizar es la unicidad.
– Kyle Strand
10 de febrero de 2016 a las 21:27
-
Ni siquiera sabía hasta ahora que hay sobrecargas de los operadores de comparación para std::pair.
– zett42
6 de marzo de 2017 a las 1:50
-
@KyleStrand, ¿cómo es esto un problema? Un operador de comparación no viola la unicidad. Además, solo puede definir un operador de comparación como tercer argumento para
map
, no por el tipo en sí. El código hablado y, por lo tanto, la claridad del código definitivamente respalda la sugerencia de bames53– Hielo fuego
20 de marzo de 2019 a las 8:08
-
@IceFire Creo que lo que estaba tratando de decir era que no querría definir un operador que implique un orden lógico en un tipo que no se supone que admita el concepto semántico de orden, porque podría ser mal utilizado. Pero obviamente usando
pair
en cambio, en realidad no evita ese problema. Creo que su sugerencia de proporcionar el operador como unmap
argumento es la solución correcta.– Kyle Strand
20 de marzo de 2019 a las 14:18
ApiladoTorcido
Normalmente resuelvo este tipo de problema así:
struct Point {
int x;
int y;
};
inline bool operator<(const Point& p1, const Point& p2) {
if (p1.x != p2.x) {
return p1.x < p2.x;
} else {
return p1.y < p2.y;
}
}
-
Esto es explícito, lo cual es bueno. Solo tenga en cuenta que esto es lo mismo que
typedef std::pair<int, int> Point;
– GManNickG
11 de julio de 2009 a las 0:28
-
Je, hasta ahora no sabía que std::pair tiene operator
– Apilado torcido
11 de julio de 2009 a las 0:33
-
@GManNickG excepto la interfaz de
x
yy
cual esfirst
ysecond
parastd::pair
.– rubenvb
16 de julio de 2013 a las 19:51
-
Esto es muy bueno porque también se puede usar para claves que contienen más de 2 campos.
– azulado
20 de julio de 2016 a las 9:55
-
También puede agregar un funtor de comparación como argumento de plantilla del mapa:
std::map<Point, std::string, PointComp> mapping;
– orzechow
8 de marzo de 2018 a las 10:11
Boost tiene un contenedor de mapas que usa uno o más índices.
-
También se puede lograr usando tuplas de impulso.
– Frizi
6 de agosto de 2012 a las 23:29
¿Cuáles son los requisitos de una clase que se utilizará como clave?
El mapa debe poder decir si el valor de una clave es menor que el valor de otra clave: por defecto, esto significa que (clave1
La plantilla de mapa también implementa un constructor sobrecargado que le permite pasar una referencia a un objeto de función de tipo key_compare, que puede implementar el operador de comparación: de modo que, alternativamente, la comparación se puede implementar como un método de este objeto de función externo, en lugar de necesita ser horneado en cualquier tipo de clave.
Esto introducirá múltiples claves enteras en un entero grande, en este caso, un _int64. Se compara como un _int64, también conocido como long long (la declaración de tipos más fea que existe. short short short short, solo sería un poco menos elegante. Hace 10 años se llamaba vlong. Mucho mejor. Tanto para “progreso”), así que no hay comparación se necesita la función.
#define ULNG unsigned long
#define BYTE unsigned char
#define LLNG long long
#define ULLNG unsigned long long
// --------------------------------------------------------------------------
ULLNG PackGUID(ULNG SN, ULNG PID, BYTE NodeId) {
ULLNG CompKey=0;
PID = (PID << 8) + NodeId;
CompKey = ((ULLNG)CallSN << 32) + PID;
return CompKey;
}
Habiendo proporcionado esta respuesta, dudo que esto funcione para usted, ya que necesita dos teclas separadas y distintas para navegar en 2 dimensiones, X e Y.
Por otro lado, si ya tiene la coordenada XY y solo desea asociar un valor con esa clave, esto funciona espectacularmente, porque una comparación _int64 toma el mismo tiempo que cualquier otra comparación de enteros en chips Intel X86: 1 reloj.
En este caso, la comparación es 3 veces más rápida en esta clave sintética que en una clave compuesta triple.
Si usa esto para crear una hoja de cálculo escasamente poblada, haría RX usando 2 árboles distintos, uno anidado dentro del otro. Haga que la dimensión Y sea “el jefe” y busque primero el espacio Y hasta la resolución antes de pasar a la dimensión X. Las hojas de cálculo son más altas que anchas, y siempre desea que la primera dimensión en cualquier clave compuesta tenga la mayor cantidad de valores únicos.
Este arreglo crearía un mapa para la dimensión Y que tendría un mapa para la dimensión X como sus datos. Cuando llega a una hoja en la dimensión Y, comienza a buscar en la dimensión X la columna en la hoja de cálculo.
Si desea crear un sistema de hoja de cálculo muy potente, agregue una dimensión Z de la misma manera y utilícela, como ejemplo, para las unidades organizativas. Esta es la base de un sistema de presupuesto/pronóstico/contabilidad muy poderoso, uno que permite que las unidades de administración tengan muchas cuentas de detalles sangrientos para rastrear los gastos de administración y demás, y que esas cuentas no ocupen espacio para las unidades de línea que tienen sus propios tipos. de detalle a rastrear.
-
Creo que meter dos largos en un _int64, siempre que el alto largo sea Y y el bajo largo sea X, buscará primero el espacio Y y luego el espacio X, ya que todos los valores con el mismo largo alto (mismo valor Y) serán iguales, dejando el bajo largo (X espacio) para desempatar.
– usuario2548100
12/09/2013 a las 22:33
Creo que para su caso de uso, std::pair
, como se sugiere en la respuesta de David Norman, es la mejor solución. Sin embargo, desde C++11 también puedes usar std::tuple
. Las tuplas son útiles si tiene más de dos claves, por ejemplo, si tiene coordenadas 3D (es decir, x
, y
y z
). Entonces no tiene que anidar pares o definir un comparador para un struct
. Pero para su caso de uso específico, el código podría escribirse de la siguiente manera:
int main() {
using tup_t = std::tuple<int, int>;
std::map<tup_t, int> m;
m[std::make_tuple(78, 26)] = 476;
tup_t t = { 12, 45 }; m
for (auto const &kv : m)
std::cout << "{ " << std::get<0>(kv.first) << ", "
<< std::get<1>(kv.first) << " } => " << kv.second << std::endl;
return 0;
}
Producción:
{ 12, 45 } => 102
{ 78, 26 } => 476
Nota: Ya que C++17 trabajar con tuplas se ha vuelto más fácil, especialmente si desea acceder a múltiples elementos simultáneamente. Por ejemplo, si usa encuadernación estructuradapuede imprimir la tupla de la siguiente manera:
for (auto const &[k, v] : m) {
auto [x, y] = k;
std::cout << "{ " << x << ", " << y << " } => " << v << std::endl;
}
-
Creo que meter dos largos en un _int64, siempre que el alto largo sea Y y el bajo largo sea X, buscará primero el espacio Y y luego el espacio X, ya que todos los valores con el mismo largo alto (mismo valor Y) serán iguales, dejando el bajo largo (X espacio) para desempatar.
– usuario2548100
12/09/2013 a las 22:33
Mateo Italia
Utilice estándar::par. Mejor incluso usar QHash<QPair<int,int>,int>
si tiene muchas de esas asignaciones.
Puede introducir fácil y legítimamente dos largos en un _int64, o como en mi respuesta a continuación, un número de serie, PID y NodeId. Dado que MAX_PID es (1
– usuario1899861
9 de septiembre de 2013 a las 5:59
Suponiendo que no desea iterar el mapa en un orden específico, use un mapa hash como std::unordered_map. Mucho más eficiente, especialmente cuando tienes tantos valores.
– hyde
9 de septiembre de 2013 a las 7:16