2012-06-11 6 views
5

Mam obiekt, który ma pary wartości zastępczych używanych do prostego kodowania/dekodowania (nie dla bezpieczeństwa, tylko dla wygody, zbyt skomplikowane, aby wyjaśnić to wszystko tutaj). To jest w postaciJavascript: Szybko szukam wartości w obiekcie (jak możemy z właściwościami)

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

gdzie „x” ma wartość zakodowania i „r” jest wartością dekodowane.

Dekodowanie jest proste: przechodzę przez znaki ciągu znaków i sprawdzam wartość charAt(i) w obiekcie za pomocą nawiasów: obj[ str.charAt(i) ]. (Pomijam czek, aby sprawdzić, czy potrzebujemy wersji wielkiej lub małej (wszystkie klawisze/wartości w obiekcie są małe), ale to dość proste.)

Do kodowania, oczywiście muszę szukać wartość w obiekcie, a nie właściwość. Obecnie przeglądam właściwości pętli for ... in ... i sprawdzam wartości pod kątem wartości charAt(i). Mój aktualny kod to:

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); 

Jestem przekonany, że powinien istnieć skuteczniejszy sposób robienia tego. (Oczywiście posiadanie odwróconego obiektu, {y: x}, jest opcją, ale niezbyt dobrą.) Czy to najlepszy sposób, czy jest lepszy? Zasadniczo, chciałbym móc zrobić var prop = obj[value] tak jak mogę zrobić var value = obj[prop].

Odpowiedz

5

Jest bardziej wydajny pętli tylko raz wcześniej stworzyć odwrotny mapę:

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) 

Zamiast robić str.length * map.length, ty” Zajmę się operacjami map.length + str.length.

+0

Tak! Zrobiłbym dwa razy, gdybym mógł, ponieważ łączy w sobie obie sugerowane ulepszenia. Jest to zdecydowanie moja akceptowana odpowiedź (poza żadną inną niesamowitą wersją ...). Dzięki! –

2

Możesz utworzyć odwróconą wersję mapowania programowo (zamiast ręcznie) i użyć go zamiast tego.

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

Wiesz co? Jesteś geniuszem ...;) To jedna z tych chwil "DUH" dla mnie. Mapowanie ręczne zdecydowanie nie wchodziło w grę, zwłaszcza jeśli chcę rozszerzyć zakres oryginału. (Widziałem kod, który ma dwie wersje dość długich par klucz/wartość, i wzdrygam się na myśl o tym, ile czasu spędziłem na pisaniu i edytowaniu w miarę rozwoju kodu.) –

0

Jeśli szukasz kluczy do tablic, sprawdź tutaj.

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

Odwrotną koder byłoby bardziej sensowne, ale można napisać funkcję zastąpić bez wszystkich 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; 
}); 

Zwrócona wartość: (String) Emxxz-Azixso

+0

Nie miałem pojęcia, że ​​możesz przejść funkcja do zastąpienia w ten sposób! Zakładam więc, że aktualna wartość to_replace (/./) jest przekazywana do funkcji, stąd w? O wiele bardziej elegancka i czytelna wersja, na pewno o tym pomyślę. –

+0

@kennebec nadal potrzebujesz sprawdzenia 'hasOwnProperty', aby uniknąć zbędnych danych z prototypowych rozszerzeń. Zadeklarowane wartości zastąpią je, ale może zwrócić dopasowanie zamiast podnieść błąd, gdy nie było. –

+0

@kennebec: Zgadzam się z Ricardo w tej sprawie. Chociaż to wszystko jest kodem, który piszę, zawsze lepiej być bezpiecznym niż żałować. Lubię mieć dobre nawyki.Myślę, że 'hasOwnProperty' powinno wystarczyć. Powód, dla którego miałem 'propertyIsEnumerable', wynika z [tej informacji z Eloquent JavaScript] (http://eloquentjavascript.net/chapter8.html#p51c5b387). –