JavaScript kết hợp nhiều mảng

Đó là bởi vì sẽ mất rất nhiều thời gian và đến một lúc nào đó bạn sẽ có quá nhiều kết hợp mà chúng sẽ không vừa với một mảng.

Mục lục

Bỏ qua mục lục

  1. Điểm khởi đầu
  2. phạm vi lỗi
  3. Tránh RangeErrors
  4. Nó chậm
  5. Độ dài của mảng đầu vào vẫn còn hạn chế
  6. Nghĩ về các lựa chọn thay thế

Điểm khởi đầu

Theo "kết hợp mục mảng", tôi đang đề cập đến bài đăng trên blog của mình từ hôm qua. Tìm tất cả các kết hợp có thể có của các mục mảng trong JS

Đây là mã

const getCombinations = [items] =>
  items.reduce[[combos, item] => {
    const newCombos = combos.map[[combo] => combo.concat[item]]
    combos.push[[item], ...newCombos]
    return combos
  }, []]

getCombinations[[1, 2, 3]]
//=> [[1],  [2],  [1, 2],  [3],  [1, 3],  [2, 3],  [1, 2, 3]]

phạm vi lỗi

Mã ném nếu độ dài của mảng đầu vào quá dài. Trong Firefox giới hạn là 20

getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
  • Trong Firefox, thông báo lỗi là "quá nhiều đối số chức năng. "
  • Trong Chrome, Edge, Safari và Nút. js, thông báo lỗi là "Vượt quá kích thước ngăn xếp cuộc gọi tối đa. "

Thông báo lỗi của Firefox có vẻ hữu ích hơn vì vấn đề là

getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
1 được gọi với quá nhiều đối số. Trong Firefox, giới hạn là 500.000 mục

;[].push[...Array[500_000]] // OK
;[].push[...Array[500_001]] // RangeError

Tránh RangeErrors

Chúng tôi có thể cố gắng tránh vấn đề bằng cách tránh hoàn toàn cú pháp lây lan

 const getCombinations = [items] =>
   items.reduce[[combos, item] => {
-    const newCombos = combos.map[[combo] => combo.concat[item]]
-    combos.push[[item], ...newCombos]

+    combos.forEach[[combo] => combos.push[combo.concat[item]]]
+    combos.push[[item]]

     return combos
   }, []]

[Tôi nghĩ rằng điều này cũng sẽ tăng hiệu suất, nhưng có vẻ như không. Có ý nghĩa mặc dù. chúng tôi tránh lặp qua

getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
2, điều này tốt, nhưng bây giờ chúng tôi đang gọi
getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
1 nhiều lần nữa chỉ với một đối số. ]

Nó chậm

Giờ đây, các mảng đầu vào lớn hơn hoạt động, nhưng việc kết hợp các mảng đầu vào lớn ngày càng chậm

console.time[]
getCombinations[Array.from[{ length: 20 }]]
console.timeEnd[] //=> ~200ms [on my machine]

console.time[]
getCombinations[Array.from[{ length: 21 }]]
console.timeEnd[] //=> ~400ms [on my machine]

console.time[]
getCombinations[Array.from[{ length: 22 }]]
console.timeEnd[] //=> ~800ms [on my machine]

console.time[]
getCombinations[Array.from[{ length: 23 }]]
console.timeEnd[] //=> ~1800ms [on my machine]

console.time[]
getCombinations[Array.from[{ length: 24 }]]
console.timeEnd[] //=> ~4200ms [on my machine]

Không ai có thời gian để chờ đợi lâu như vậy

Độ dài của mảng đầu vào vẫn còn hạn chế

Trong Firefox, độ dài tối đa của một mảng dường như là

getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
0

Array[2 ** 32 - 1] // OK
Array[2 ** 32] // RangeError: invalid array length

Độ dài của mảng được trả về bởi

getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
1 tình cờ là
getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
2

getCombinations[Array.from[{ length: 1 }]].length === 2 ** 1 - 1 // true
getCombinations[Array.from[{ length: 2 }]].length === 2 ** 2 - 1 // true
getCombinations[Array.from[{ length: 3 }]].length === 2 ** 3 - 1 // true
// ...
getCombinations[Array.from[{ length: 10 }]].length === 2 ** 10 - 1 // true
getCombinations[Array.from[{ length: 11 }]].length === 2 ** 11 - 1 // true
getCombinations[Array.from[{ length: 12 }]].length === 2 ** 12 - 1 // true
// ...and so on

[Bài toán tính tổng các tổ hợp. ]

Nói cách khác, độ dài tối đa của mảng đầu vào là 32

Nhưng các mảng đầu vào dài sẽ không thực tế vì việc nhận tất cả các kết hợp sẽ mất quá nhiều thời gian. Thêm vào đó sẽ có khá nhiều sự kết hợp.

getCombinations[Array.from[{ length: 19 }]] // OK
getCombinations[Array.from[{ length: 20 }]] // RangeError
0 = 4.294.967.295. Hơn 4 tỷ

Nghĩ về các lựa chọn thay thế

Được rồi, vì vậy độ dài của mảng đầu vào được giới hạn ở 32 [ít nhất là trong Firefox] và việc nhận được tất cả các kết hợp sẽ mất nhiều thời gian, vì vậy hãy suy nghĩ

Chủ Đề