2012-06-11 53 views
5

Tôi có một đối tượng có cặp giá trị thay thế được sử dụng để mã hóa/giải mã đơn giản (không phải để bảo mật, chỉ để thuận tiện;). Nó ở dạngJavascript: Giá trị tra cứu nhanh chóng trong đối tượng (như chúng ta có thể với thuộc tính)

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

trong đó 'x' là giá trị khi được mã hóa và 'y' là giá trị được giải mã.

Giải mã rất đơn giản: Tôi lặp qua các ký tự của chuỗi và tra cứu giá trị charAt(i) trong đối tượng qua ngoặc đơn: obj[ str.charAt(i) ]. (Tôi bỏ qua kiểm tra để xem liệu chúng ta cần một phiên bản chữ hoa hay chữ thường (tất cả các khóa/giá trị trong đối tượng là chữ thường), nhưng đơn giản là đủ.)

Để mã hóa, tất nhiên tôi phải tìm kiếm giá trị trong đối tượng, chứ không phải thuộc tính. Hiện tại, tôi đang lặp qua các thuộc tính với vòng lặp for ... in ... và kiểm tra các giá trị so với giá trị charAt(i). Mã hiện tại của tôi là:

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

Tôi thật sự cảm thấy cần phải có cách hiệu quả hơn để thực hiện việc này. (Tất nhiên có một đối tượng được đảo ngược, {y: x}, là một lựa chọn. Nhưng không phải là một lựa chọn tốt.) Đây có phải là cách tốt nhất, hay là tốt hơn? Về bản chất, tôi rất muốn có thể làm var prop = obj[value] giống như tôi có thể làm var value = obj[prop].

Trả lời

5

Đó là hiệu quả hơn để lặp chỉ một lần trước để tạo ra một bản đồ ngược lại:

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) 

Thay vì làm str.length * map.length, bạn' ll làm map.length + str.length hoạt động.

+0

Có! Tôi sẽ upvote bạn hai lần nếu tôi có thể, vì điều này kết hợp cả hai cải tiến được đề xuất thành một. Điều này chắc chắn là câu trả lời được chấp nhận của tôi (chặn bất kỳ phiên bản tuyệt vời nào khác ...). Cảm ơn! –

2

Bạn có thể tạo phiên bản lập bản đồ được đảo ngược theo lập trình (thay vì bằng tay) và sử dụng nó thay thế.

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

Bạn biết không? Bạn là một thiên tài ...;) Đây là một trong những khoảnh khắc "DUH" cho tôi. Lập bản đồ bằng tay chắc chắn không phải là một lựa chọn, đặc biệt là nếu tôi muốn có thể mở rộng phạm vi của bản gốc. (Tôi đã nhìn thấy mã có hai phiên bản của cặp khóa/giá trị khá dài, và tôi xoay quanh suy nghĩ về thời gian đã được gõ vào chúng, và chỉnh sửa như mã được phát triển.) –

0

Nếu bạn đang tìm kiếm các phím mảng kiểm tra tại đây.

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

Một bộ mã hóa ngược lại sẽ có ý nghĩa hơn, nhưng bạn có thể viết một hàm thay thế mà không cần tất cả các 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; 
}); 

giá trị trả về: (String) Emxxz-Azixso

+0

Tôi không có ý tưởng bạn có thể vượt qua một chức năng để thay thế như thế! Tôi giả định sau đó rằng giá trị hiện tại to_replace (/./) được chuyển đến hàm, do đó w? Nhiều phiên bản thanh lịch và dễ đọc hơn, tôi chắc chắn sẽ nghĩ về điều này. –

+0

@kennebec bạn vẫn cần kiểm tra 'hasOwnProperty' để tránh dữ liệu không liên quan từ các phần mở rộng mẫu thử nghiệm. Các giá trị được khai báo sẽ ghi đè lên các giá trị đó, nhưng nó có thể trả lại kết quả khớp thay vì tăng lỗi khi không có lỗi nào. –

+0

@kennebec: Tôi đồng ý với Ricardo về điều đó. Mặc dù đây là tất cả các mã tôi đang viết bản thân mình, luôn luôn tốt hơn để được an toàn hơn xin lỗi. Và tôi thích tự mình có thói quen tốt.Tôi nghĩ rằng 'hasOwnProperty' nên là đủ. Lý do tôi có 'propertyIsEnumerable' là do [thông tin này từ JavaScript Eloquent] (http://eloquentjavascript.net/chapter8.html#p51c5b387). –

Các vấn đề liên quan