Usando un número entero como clave en una matriz asociativa en JavaScript

102

Cuando creo una nueva matriz de JavaScript y uso un número entero como clave, cada elemento de esa matriz hasta el número entero se crea como indefinido.

Por ejemplo:

var test = new Array();
test[2300] = 'Some string';
console.log(test);

generará 2298 indefinidos y una 'Alguna cadena'.

¿Cómo debo hacer que JavaScript use 2300 como una cadena en lugar de un número entero, o cómo debo evitar que instancia 2299 índices vacíos?

Peter Mortensen
fuente

Respuestas:

128

Usa un objeto, como dice la gente. Sin embargo, nota que puede no tener número entero llaves. JavaScript convertirá el número entero en una cadena . Las siguientes salidas 20, no indefinidas:

var test = {}
test[2300] = 20;
console.log(test["2300"]);
Claudiu
fuente
12
+1 Tenga en cuenta que esto es incluso cierto para las matrices. ver stackoverflow.com/questions/1450957/…
bobince
1
@bobince: Internamente, seguro. Sin embargo, lógicamente , las matrices tienen "claves" enteras.
Lightness Races in Orbit
1
Tenga en cuenta que el uso de un entero como clave cambiará la longitud de su matriz. Definitivamente deberías usar Object en su lugar. Solo quería usar la identificación de Facebook como clave, y JSON.stringify bloquearía mi máquina;)
Krystian
2
@LightnessRacesinOrbit Los detalles internos aún pueden filtrarse y morderte. Vea esta versión simplificada de lo que encontré hoy: jsfiddle.net/cincodenada/pseujLex/2 Puede parecer artificial cuando se reduce, pero era una parte sensible de un script más grande (y es un poco menos artificial en CoffeeScript: jsfiddle.net/ cincodenada / oojr7Ltn / 2 ). Este aparente detalle de implementación me costó un poco de búsqueda de errores hoy.
cincodenada
1
Una pequeña nota para números no enteros: 0.25y .25resuelve en la misma cadena "0.25". Así que si estás usando las teclas fraccionaria, podrá recuperar la propiedad de una llave ajustar de forma numérica 0.25usando 0.25, .25, "0.25"pero no ".25".
Sandy Gifford
34

Puedes usar un objeto:

var test = {}
test[2300] = 'Some string';
Annie
fuente
16
Todavía se lanza a la cuerda.
drew010
1
@ drew010 sí, los objetos de Javascript permiten indexar solo con cadenas.
Pithikos
22

Como dice la gente, JavaScript convertirá una cadena de número en entero, por lo que no es posible usarlo directamente en una matriz asociativa, pero creo que los objetos funcionarán para usted de manera similar.

Puedes crear tu objeto:

var object = {};

Y agregue los valores como funciona la matriz:

object[1] = value;
object[2] = value;

Esto te dará:

{
  '1': value,
  '2': value
}

Después de eso, puede acceder a él como una matriz en otros idiomas obteniendo la clave:

for(key in object)
{
   value = object[key] ;
}

Lo he probado y funciona.

Jesúslg123
fuente
17

Si el caso de uso es almacenar datos en una colección, ECMAScript 6 proporciona el Maptipo.

Solo es más pesado de inicializar.

Aquí hay un ejemplo:

const map = new Map();
map.set(1, "One");
map.set(2, "Two");
map.set(3, "Three");

console.log("=== With Map ===");

for (const [key, value] of map) {
    console.log(`${key}: ${value} (${typeof(key)})`);
}

console.log("=== With Object ===");

const fakeMap = {
    1: "One",
    2: "Two",
    3: "Three"
};

for (const key in fakeMap) {
    console.log(`${key}: ${fakeMap[key]} (${typeof(key)})`);
}

Resultado:

=== With Map ===
1: One (number)
2: Two (number)
3: Three (number)
=== With Object ===
1: One (string)
2: Two (string)
3: Three (string)
Pragmateek
fuente
11

Compilando otras respuestas:

Objeto

var test = {};

Cuando se usa un número como clave de una nueva propiedad, el número se convierte en una cadena:

test[2300] = 'Some string';
console.log(test['2300']);
// Output: 'Some string'

Al acceder al valor de la propiedad con el mismo número, el número se convierte nuevamente en una cadena:

console.log(test[2300]);
// Output: 'Some string'

Sin embargo, al obtener las claves del objeto, no se volverán a convertir en números:

for (var key in test) {
    console.log(typeof key);
}
// Output: 'string'

Mapa

ECMAScript 6 permite el uso del objeto Map ( documentación , una comparación con Object ). Si su código está destinado a ser interpretado localmente o la tabla de compatibilidad de ECMAScript 6 parece lo suficientemente verde para sus propósitos, considere usar un mapa:

var test = new Map();
test.set(2300, 'Some string');
console.log(test.get(2300));
// Output: 'Some string'

No se realiza ninguna conversión de tipo, para bien o para mal:

console.log(test.get('2300'));
// Output: undefined
test.set('2300', 'Very different string');
console.log(test.get(2300));
// Output: 'Some string'
error de palabra
fuente
4

Utilice un objeto en lugar de una matriz. Las matrices en JavaScript no son matrices asociativas. Son objetos con magia asociada con cualquier propiedad cuyos nombres parecen números enteros. Esa magia no es lo que desea si no los está usando como una estructura tradicional similar a una matriz.

var test = {};
test[2300] = 'some string';
console.log(test);
bdukes
fuente
1
Ellos pueden ser matrices asociativas, pero sólo porque también son objetos que pueden haber nombrados propiedades establecidas. Pero esto solo hace que las cosas sean ridículamente confusas, por lo que sí, los objetos son mucho mejores de usar.
Graza
Las matrices nunca pueden ser asociativas Graza. Si intenta usar claves en una matriz y luego iterar sobre ellas, notará que también está iterando a través de todos los métodos y propiedades predeterminados de las matrices -> no muy deseable.
Swizec Teller
@Swizec - exactamente por qué dije "ridículamente confuso". Usted puede utilizar una matriz como una matriz asociativa - que es como pares de nombre / valor, pero nunca se quiere iterar ellos! (Simplemente estaba señalando un tecnicismo, definitivamente no es algo que recomendaría hacer)
Graza
sí, pero al iterar no están en ningún orden en particular (es decir, el orden no está garantizado), que sería el punto de numerarlos, así que es mucho peor que simplemente confundir.
Julix
3

Intente usar un objeto, no una matriz:

var test = new Object(); test[2300] = 'Some string';
Jeff Hammerbacher
fuente
3
Este es definitivamente el camino a seguir. De esta manera, no creará una matriz de 2300 entradas para almacenar una sola cadena.
Krystian
2
Las matrices @Krystian JS son matrices falsas. Ejecute var a = []; a[Math.pow(2, 30)] = 'hello';y no verá que el uso del navegador / memoria se dispare en más de un gigabyte, pero verá que a.lengthes 1073741824. Las máquinas virtuales almacenan claramente algunas "matrices" usando alguna otra estructura de datos, supongo que simplemente una tabla hash, al menos si son lo suficientemente escasos.
Andy
2

Obtenga el valor de una propiedad de matriz asociativa cuando el nombre de la propiedad es un número entero:

Comenzando con una matriz asociativa donde los nombres de las propiedades son números enteros:

var categories = [
    {"1": "Category 1"},
    {"2": "Category 2"},
    {"3": "Category 3"},
    {"4": "Category 4"}
];

Empuje elementos a la matriz:

categories.push({"2300": "Category 2300"});
categories.push({"2301": "Category 2301"});

Recorra la matriz y haga algo con el valor de la propiedad.

for (var i = 0; i < categories.length; i++) {
    for (var categoryid in categories[i]) {
        var category = categories[i][categoryid];
        // Log progress to the console
        console.log(categoryid + ": " + category);
        //  ... do something
    }
}

La salida de la consola debería verse así:

1: Category 1
2: Category 2
3: Category 3
4: Category 4
2300: Category 2300
2301: Category 2301

Como puede ver, puede sortear la limitación de la matriz asociativa y hacer que el nombre de una propiedad sea un número entero.

NOTA: La matriz asociativa en mi ejemplo es el contenido JSON que tendría si serializara un objeto Dictionary <string, string> [].

Jason Williams
fuente
0

Utilice un objeto, con un número entero como clave, en lugar de una matriz.

Plataforma superior
fuente
0

A veces utilizo prefijos para mis claves. Por ejemplo:

var pre = 'foo',
    key = pre + 1234

obj = {};

obj[key] = val;

Ahora no tienes ningún problema para acceder a ellos.

pictus
fuente