2012-06-11 4 views
5

Tengo un objeto que tiene pares de valores de reemplazo utilizados para la codificación/decodificación simple (no por seguridad, solo por comodidad, demasiado complicado para explicarlo todo aquí) Está en la formaJavascript: valor de búsqueda rápida en el objeto (como podemos con las propiedades)

var obj = {x: y, 
      x: y, 
      ... 
      }; 

donde 'x' es el valor cuando codifica y 'y' es el valor decodificado.

La decodificación es simple: recorro los caracteres de la cadena y busco el valor charAt(i) en el objeto mediante corchetes: obj[ str.charAt(i) ]. (Dejo fuera el cheque para ver si necesitamos una versión en mayúsculas o minúsculas (todas las claves/valores en el objeto son minúsculas), pero eso es bastante simple.)

Para codificar, por supuesto tengo que buscar el valor en el objeto, en lugar de la propiedad. Actualmente, estoy recorriendo las propiedades con un bucle for ... in ... y comprobando los valores con el valor charAt(i). Mi código actual es:

var i, j, 
    output = '', 
    str = 'Hello World!', 
    obj = {'s':'d', 
      'm':'e', 
      'e':'h', 
      'x':'l', 
      'z':'o', 
      'i':'r', 
      'a':'w', 
      'o':'!', 
      '-':' '}; 
for (i = 0; i < str.length; i++) { 
    for (j in obj) { 
     if (Object.prototype.hasOwnProperty.call(obj, j) && 
      Object.prototype.propertyIsEnumerable.call(obj, j)) { 
      if (obj[j] === str.charAt(i)) { 
       output += j; 
       break; 
      } else if (obj[j].toUpperCase() === str.charAt(i)) { 
       output += j.toUpperCase(); 
       break; 
      } 
     } 
    } 
} 
alert(output); 

Innatamente siento que debería haber una forma más eficiente de hacerlo. (Por supuesto tener un objeto invertido, {y: x}, es una opción, pero no una buena). ¿Es esta la mejor manera, o hay una mejor? En esencia, me encantaría poder hacer var prop = obj[value] del mismo modo que puedo hacer var value = obj[prop].

Respuesta

5

Es más eficiente para recorrer sólo una vez antes para crear un mapa inversa:

var str = "Hello World!", 
    output = '', 
    map = { 
     "s":"d", "m":"e", 
     "e":"h", "x":"l", 
     "z":"o", "i":"r", 
     "a":"w", "o":"!", 
     "-":" " 
    }, 
    reverseMap = {} 

for (j in map){ 
    if (!Object.prototype.hasOwnProperty.call(map, j)) continue 
    reverseMap[map[j]] = j 
} 

output = str.replace(/./g, function(c){ 
    return reverseMap[c] || reverseMap[c.toLowerCase()].toUpperCase() 
}) 

console.log(output) 

En vez de hacer str.length * map.length, que' ll hacer map.length + str.length operaciones.

+0

¡Sí! Te podría haber votado dos veces si pudiera, ya que combina las dos mejoras sugeridas en una. Esta es definitivamente mi respuesta aceptada (salvo que haya otra versión increíble ...). ¡Gracias! –

2

Puede crear una versión inversa de la asignación mediante programación (en lugar de a mano) y usarla en su lugar.

var rev = {} 
for (key in obj) 
    rev[obj[key]] = key 
+0

¿Sabes qué? Eres un genio ...;) Este es uno de esos momentos "DUH" para mí. El mapeo manual no era una opción, especialmente si quiero ampliar el alcance del original. (He visto código que tiene dos versiones de pares de clave/valor bastante largos, y me estremezco al pensar en cuánto tiempo me tomó escribirlos y editarlos a medida que se desarrollaba el código.) –

0

Si está buscando las teclas de matriz, marque aquí.

https://raw.github.com/kvz/phpjs/master/functions/array/array_keys.js

function array_keys (input, search_value, argStrict) { 
    var search = typeof search_value !== 'undefined', tmp_arr = [], strict = !!argStrict, include = true, key = ''; 

    if (input && typeof input === 'object' && input.change_key_case) { 
     return input.keys(search_value, argStrict); 
    } 

    for (key in input) { 
     if (input.hasOwnProperty(key)) { 
      include = true; 
      if (search) { 
       if (strict && input[key] !== search_value) include = false; 
       else if (input[key] != search_value) include = false; 
      } 
      if (include) tmp_arr[tmp_arr.length] = key; 
     } 
    } 

    return tmp_arr; 
} 
3

Un codificador inverso tendría más sentido, pero se puede escribir una función de reemplazar sin todos los etc.tests hasOwnProperty.

var str= 'Hello World!', 
obj={ 
    's':'d', 
    'm':'e', 
    'e':'h', 
    'x':'l', 
    'z':'o', 
    'i':'r', 
    'a':'w', 
    'o':'!', 
    '-':' ' 
} 
str= str.replace(/./g, function(w){ 
    for(var p in obj){ 
     if(obj[p]=== w) return p; 
     if(obj[p]=== w.toLowerCase()) return p.toUpperCase(); 
    }; 
    return w; 
}); 

valor devuelto: (Cadena) Emxxz-Azixso

+0

No tenía idea de que pudiera pasar una función para reemplazar así! Supongo que el valor actual para volver a colocar (/./) se pasa a la función, por lo tanto, el w? Versión mucho más elegante y legible, definitivamente pensaré en esto. –

+0

@kennebec, usted todavía necesita la verificación 'hasOwnProperty' para evitar datos extraños de las extensiones del prototipo. Los valores declarados los anularán, pero podrían devolver una coincidencia en lugar de generar un error cuando no los hubo. –

+0

@kennebec: Estoy de acuerdo con Ricardo en eso. Aunque esto es todo código que me escribo, siempre es mejor estar a salvo que lamentar. Y me gusta tener buenos hábitos.Creo que 'hasOwnProperty' debería ser suficiente. La razón por la que tuve 'propertyIsEnumerable' se debe a [esta información de Eloquent JavaScript] (http://eloquentjavascript.net/chapter8.html#p51c5b387). –

Cuestiones relacionadas