Hướng dẫn javascript dictionary vs object - từ điển javascript so với đối tượng

Trong JavaScript, cả ObjectMap đều có thể được sử dụng cho "Từ điển" (Cửa hàng cặp có giá trị khóa) khi chúng cho phép bạn thực hiện tất cả các hoạt động đọc và ghi cơ bản mà bạn mong đợi khi làm việc với cấu trúc dữ liệu như vậy: "Đặt", "Nhận được "," Xóa "và" Phát hiện "các khóa, Giá trị & Mục nhập. Trong lịch sử, và trước Map thậm chí còn tồn tại trong JavaScript, chúng tôi đã sử dụng Object cho từ điển. Tuy nhiên, điều đó hoàn toàn ổn, có những khác biệt quan trọng làm cho Map thích hợp hơn trong một số trường hợp và điều đó có thể được tìm thấy ở đây: https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/map# object_vs._maps

Về mặt cá nhân, trong trường hợp tôi hiện đang làm việc, tôi muốn sử dụng Map qua Object vì tôi cảm thấy rằng Map sẽ phù hợp hơn cho những gì tôi đang cố gắng đạt được vào lúc này: từ điển lớn với hàng trăm triệu /Viết các hoạt động và dựa trên điểm chuẩn tùy chỉnh, Map có vẻ nhanh hơn nhiều so với Object (một lần nữa, trong trường hợp của tôi).

Thật không may, khi lặp lại trên từ điển Map của tôi (một Map có thể sử dụng được, vì vậy nó có thể được lặp trực tiếp với

// Map dictionary -> DOESN'T WORK AS IS!
const numbers = new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
]);

function compute(numbers) {
  /*
   * The values() method returns a new iterator object that contains the values
   * for each element in the Map object in insertion order.
   */
  for (number of numbers.values()) {
    console.log('number:', number);

    const squared = number * number;

    if (!numbers.has(`${squared}`)) {
      // "Iterate-and-Mutate" anti-pattern/problem:
      numbers.set(`${squared}`, squared);
    }
  }

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);
7), tôi đang phải đối mặt với vấn đề "lặp lại và đột biến" Tương tự Map trong vòng lặp. Đó là một người chống lại!"Iterate-and-Mutate" problem: when iterating on a Map, you are not supposed to mutate that same Map within iterations. That's an anti-pattern!

Với Object (không thực hiện giao thức lặp và do đó các đối tượng không được lặp lại trực tiếp bằng cách sử dụng

// Map dictionary -> DOESN'T WORK AS IS!
const numbers = new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
]);

function compute(numbers) {
  /*
   * The values() method returns a new iterator object that contains the values
   * for each element in the Map object in insertion order.
   */
  for (number of numbers.values()) {
    console.log('number:', number);

    const squared = number * number;

    if (!numbers.has(`${squared}`)) {
      // "Iterate-and-Mutate" anti-pattern/problem:
      numbers.set(`${squared}`, squared);
    }
  }

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);
7 theo mặc định), tôi đang sử dụng Thuộc tính khóa chuỗi [khóa, giá trị] cặp. Do đó, vì tôi không lặp đi lặp lại trên từ điển, nhưng thực sự trên một bộ nhớ riêng biệt, tôi có thể viết/thay đổi từ điển của mình một cách an toàn, mà không phải đối mặt với bất kỳ vấn đề nào liên quan đến vấn đề "lặp lại và đột biến".

Khi sử dụng Map làm từ điển và để lặp và đột biến, một giải pháp là sao chép (sao chép nông hoặc sâu) từ điển, sau đó lặp lại từ điển ban đầu, nhưng chỉ làm biến đổi bản sao. Khi chu kỳ lặp kết thúc, gán bản sao cho từ điển ban đầu và xóa bản sao hiện vô dụng. Điều này đòi hỏi phải có một bản sao của từ điển Map gốc trong bộ nhớ có không gian không cần thiết.

Có cách nào tốt hơn để phá vỡ vấn đề "lặp lại" chống lại "liên quan đến từ điển Map chứ không phải nhân bản?

Cảm ơn bạn!

Examples:

  1. // Map dictionary + clone (Deep Copy) -> WORKS!
    let numbers = new Map([
      ['0', 0],
      ['1', 1],
      ['2', 2],
      ['3', 3],
      ['4', 4],
      ['5', 5],
    ]);
    
    function compute(numbers) {
      /*
       * We create a clone (Deep Copy).
       * The data itself is cloned (slow and take a lot of memory).
       */
      const clone = new Map([ ...numbers.entries() ]);
    
      // Then, we iterate on the original dictionary.
      for (number of numbers.values()) {
        console.log('number:', number);
    
        const square = number * number;
    
        if (!clone.has(`${square}`)) {
          // But we mutate the clone, not the original dictionary.
          clone.set(`${square}`, square);
        }
      }
    
      // Finally, we assign 'clone' to original dictionary 'numbers'.
      numbers = clone;
      // And delete 'clone'.
      delete clone;
    
      return numbers;
    }
    
    console.time('timer');
    const result = compute(numbers);
    console.timeEnd('timer');
    
    console.log('result:', result);
    
    9
// Object dictionary -> WORKS!
const numbers = {
  '0': 0,
  '1': 1,
  '2': 2,
  '3': 3,
  '4': 4,
  '5': 5,
};

function compute(numbers) {
  /*
   * The Object.values() method returns an array of a given object's own
   * enumerable property values, in the same order as that provided by a
   * for...in loop.
   */
  for (number of Object.values(numbers)) {
    console.log('number:', number);

    const square = number * number;

    if (!numbers[`${square}`]) {
      numbers[`${square}`] = square;
    }
  }

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);
  1. // Map dictionary + clone (Shallow Copy) -> WORKS!
    let numbers = new Map([
      ['0', 0],
      ['1', 1],
      ['2', 2],
      ['3', 3],
      ['4', 4],
      ['5', 5],
    ]);
    
    function compute(numbers) {
      /*
       * We create a clone (Shallow Copy).
       * The data itself is not cloned (faster and take less memory than Deep Copy).
       */
      const clone = new Map(numbers);
    
      // Then, we iterate on the original dictionary.
      for (number of numbers.values()) {
        console.log('number:', number);
    
        const square = number * number;
    
        if (!clone.has(`${square}`)) {
          // But we mutate the clone, not the original dictionary.
          clone.set(`${square}`, square);
        }
      }
    
      // Finally, we assign 'clone' to original dictionary 'numbers'.
      numbers = clone;
      // And delete 'clone'.
      delete clone;
    
      return numbers;
    }
    
    console.time('timer');
    const result = compute(numbers);
    console.timeEnd('timer');
    
    console.log('result:', result);
    
    0
// Map dictionary -> DOESN'T WORK AS IS!
const numbers = new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
]);

function compute(numbers) {
  /*
   * The values() method returns a new iterator object that contains the values
   * for each element in the Map object in insertion order.
   */
  for (number of numbers.values()) {
    console.log('number:', number);

    const squared = number * number;

    if (!numbers.has(`${squared}`)) {
      // "Iterate-and-Mutate" anti-pattern/problem:
      numbers.set(`${squared}`, squared);
    }
  }

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);
  1. // Map dictionary + clone (Shallow Copy) -> WORKS!
    let numbers = new Map([
      ['0', 0],
      ['1', 1],
      ['2', 2],
      ['3', 3],
      ['4', 4],
      ['5', 5],
    ]);
    
    function compute(numbers) {
      /*
       * We create a clone (Shallow Copy).
       * The data itself is not cloned (faster and take less memory than Deep Copy).
       */
      const clone = new Map(numbers);
    
      // Then, we iterate on the original dictionary.
      for (number of numbers.values()) {
        console.log('number:', number);
    
        const square = number * number;
    
        if (!clone.has(`${square}`)) {
          // But we mutate the clone, not the original dictionary.
          clone.set(`${square}`, square);
        }
      }
    
      // Finally, we assign 'clone' to original dictionary 'numbers'.
      numbers = clone;
      // And delete 'clone'.
      delete clone;
    
      return numbers;
    }
    
    console.time('timer');
    const result = compute(numbers);
    console.timeEnd('timer');
    
    console.log('result:', result);
    
    1 (chậm và lấy nhiều bộ nhớ)
// Map dictionary + clone (Deep Copy) -> WORKS!
let numbers = new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
]);

function compute(numbers) {
  /*
   * We create a clone (Deep Copy).
   * The data itself is cloned (slow and take a lot of memory).
   */
  const clone = new Map([ ...numbers.entries() ]);

  // Then, we iterate on the original dictionary.
  for (number of numbers.values()) {
    console.log('number:', number);

    const square = number * number;

    if (!clone.has(`${square}`)) {
      // But we mutate the clone, not the original dictionary.
      clone.set(`${square}`, square);
    }
  }

  // Finally, we assign 'clone' to original dictionary 'numbers'.
  numbers = clone;
  // And delete 'clone'.
  delete clone;

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);
  1. // Map dictionary + clone (Shallow Copy) -> WORKS!
    let numbers = new Map([
      ['0', 0],
      ['1', 1],
      ['2', 2],
      ['3', 3],
      ['4', 4],
      ['5', 5],
    ]);
    
    function compute(numbers) {
      /*
       * We create a clone (Shallow Copy).
       * The data itself is not cloned (faster and take less memory than Deep Copy).
       */
      const clone = new Map(numbers);
    
      // Then, we iterate on the original dictionary.
      for (number of numbers.values()) {
        console.log('number:', number);
    
        const square = number * number;
    
        if (!clone.has(`${square}`)) {
          // But we mutate the clone, not the original dictionary.
          clone.set(`${square}`, square);
        }
      }
    
      // Finally, we assign 'clone' to original dictionary 'numbers'.
      numbers = clone;
      // And delete 'clone'.
      delete clone;
    
      return numbers;
    }
    
    console.time('timer');
    const result = compute(numbers);
    console.timeEnd('timer');
    
    console.log('result:', result);
    
    2 (nhanh hơn và có ít bộ nhớ hơn bản sao sâu, nhưng vẫn ...)
// Map dictionary + clone (Shallow Copy) -> WORKS!
let numbers = new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
]);

function compute(numbers) {
  /*
   * We create a clone (Shallow Copy).
   * The data itself is not cloned (faster and take less memory than Deep Copy).
   */
  const clone = new Map(numbers);

  // Then, we iterate on the original dictionary.
  for (number of numbers.values()) {
    console.log('number:', number);

    const square = number * number;

    if (!clone.has(`${square}`)) {
      // But we mutate the clone, not the original dictionary.
      clone.set(`${square}`, square);
    }
  }

  // Finally, we assign 'clone' to original dictionary 'numbers'.
  numbers = clone;
  // And delete 'clone'.
  delete clone;

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);
  1. // Map dictionary + clone (Shallow Copy) -> WORKS!
    let numbers = new Map([
      ['0', 0],
      ['1', 1],
      ['2', 2],
      ['3', 3],
      ['4', 4],
      ['5', 5],
    ]);
    
    function compute(numbers) {
      /*
       * We create a clone (Shallow Copy).
       * The data itself is not cloned (faster and take less memory than Deep Copy).
       */
      const clone = new Map(numbers);
    
      // Then, we iterate on the original dictionary.
      for (number of numbers.values()) {
        console.log('number:', number);
    
        const square = number * number;
    
        if (!clone.has(`${square}`)) {
          // But we mutate the clone, not the original dictionary.
          clone.set(`${square}`, square);
        }
      }
    
      // Finally, we assign 'clone' to original dictionary 'numbers'.
      numbers = clone;
      // And delete 'clone'.
      delete clone;
    
      return numbers;
    }
    
    console.time('timer');
    const result = compute(numbers);
    console.timeEnd('timer');
    
    console.log('result:', result);
    
    3
// Map dictionary + fake clone -> DOESN'T WORK BECAUSE INSUFFICIENT!
let numbers = new Map([
  ['0', 0],
  ['1', 1],
  ['2', 2],
  ['3', 3],
  ['4', 4],
  ['5', 5],
]);

function compute(numbers) {
  /*
   * We create a "clone" (we believe we do, but in reality we don't!).
   * The 'clone' variable is not really a clone/copy of 'numbers'.
   * It's just a variable that points to the same data in memory.
   * Therefore, any mutation on 'numbers' will be reflected on 'clone',
   * which breaks the solution!
   */
  const clone = numbers;

  // Then, we iterate on the original dictionary.
  for (number of numbers.values()) {
    console.log('number:', number);

    const square = number * number;

    if (!clone.has(`${square}`)) {
      // But we mutate the clone, not the original dictionary.
      clone.set(`${square}`, square);
    }
  }

  // Finally, we assign 'clone' to original dictionary 'numbers'.
  numbers = clone;
  // And delete 'clone'.
  delete clone;

  return numbers;
}

console.time('timer');
const result = compute(numbers);
console.timeEnd('timer');

console.log('result:', result);