Có đúng không khi sử dụng phương thức JavaScript Array.sort () để xáo trộn?


126

Tôi đang giúp ai đó với mã JavaScript của anh ấy và mắt tôi bị bắt gặp bởi một phần trông như thế:

function randOrd(){
  return (Math.round(Math.random())-0.5);
}
coords.sort(randOrd);
alert(coords);

Mặc dù đầu tiên của tôi là: hey, cái này không thể hoạt động được! Nhưng sau đó tôi đã thực hiện một số thử nghiệm và thấy rằng nó thực sự ít nhất dường như cung cấp kết quả ngẫu nhiên độc đáo.

Sau đó, tôi đã thực hiện một số tìm kiếm trên web và gần như ở đầu trang tìm thấy một bài viết mà mã này được sao chép nhiều nhất. Trông giống như một trang web và tác giả khá đáng kính ...

Nhưng cảm giác ruột của tôi nói với tôi, rằng điều này phải sai. Đặc biệt là thuật toán sắp xếp không được chỉ định bởi tiêu chuẩn ECMA. Tôi nghĩ rằng các algoritms sắp xếp khác nhau sẽ dẫn đến các xáo trộn không đồng đều khác nhau. Một số thuật toán sắp xếp có thể thậm chí lặp vô hạn ...

Nhưng bạn nghĩ gì?

Và như một câu hỏi khác ... làm thế nào bây giờ tôi sẽ đi và đo lường kết quả của kỹ thuật xáo trộn này ngẫu nhiên như thế nào?

cập nhật: Tôi đã thực hiện một số phép đo và đăng kết quả dưới đây như một trong những câu trả lời.


chỉ cần lưu ý rằng việc làm tròn kết quả chỉ là vô số dấu hiệu
bormat

2
" Tôi thấy rằng nó dường như cung cấp kết quả ngẫu nhiên độc đáo. " - THẬT SỰ ???
Bergi

Câu trả lời:


109

Nó không bao giờ là cách xáo trộn yêu thích của tôi, một phần vì nó là cách triển khai cụ thể như bạn nói. Cụ thể, tôi dường như nhớ rằng thư viện tiêu chuẩn sắp xếp từ Java hoặc .NET (không chắc chắn) thường có thể phát hiện nếu bạn kết thúc một so sánh không nhất quán giữa một số thành phần (ví dụ: trước tiên bạn yêu cầu A < BB < Csau đó C < A).

Nó cũng kết thúc như một sự xáo trộn phức tạp hơn (về thời gian thực hiện) so với bạn thực sự cần.

Tôi thích thuật toán xáo trộn phân vùng hiệu quả bộ sưu tập thành "xáo trộn" (khi bắt đầu bộ sưu tập, ban đầu trống) và "không xáo trộn" (phần còn lại của bộ sưu tập). Ở mỗi bước của thuật toán, chọn một phần tử không xáo trộn ngẫu nhiên (có thể là phần tử đầu tiên) và hoán đổi nó với phần tử không xáo trộn đầu tiên - sau đó coi nó là xáo trộn (nghĩa là di chuyển phân vùng để bao gồm nó).

Đây là O (n) và chỉ yêu cầu các cuộc gọi n-1 đến trình tạo số ngẫu nhiên, rất hay. Nó cũng tạo ra một shuffle chính hãng - bất kỳ phần tử nào cũng có cơ hội 1 / n kết thúc ở mỗi không gian, bất kể vị trí ban đầu của nó (giả sử RNG hợp lý). Phiên bản được sắp xếp gần đúng với phân phối chẵn (giả sử rằng trình tạo số ngẫu nhiên không chọn cùng một giá trị hai lần, điều này rất khó xảy ra nếu nó trả lại gấp đôi ngẫu nhiên) nhưng tôi thấy dễ hiểu hơn về phiên bản xáo trộn :)

Cách tiếp cận này được gọi là xáo trộn Fisher-Yates .

Tôi sẽ coi đó là cách thực hành tốt nhất để mã hóa shuffle này một lần và tái sử dụng nó ở mọi nơi bạn cần để xáo trộn các mục. Sau đó, bạn không cần phải lo lắng về việc triển khai sắp xếp về độ tin cậy hoặc độ phức tạp. Đó chỉ là một vài dòng mã (mà tôi sẽ không thử trong JavaScript!)

Các bài viết trên Wikipedia về xáo trộn (và đặc biệt là phần thuật toán ngẫu nhiên) nói về sắp xếp một chiếu ngẫu nhiên - nó đáng đọc phần nói về việc triển khai kém xáo trộn nói chung, vì vậy bạn biết những gì để tránh.


5
Raymond Chen đi sâu vào tầm quan trọng có chức năng loại so sánh theo các quy tắc: blogs.msdn.com/oldnewthing/archive/2009/05/08/9595334.aspx
Jason Kresowaty

1
nếu lý luận của tôi là chính xác, phiên bản được sắp xếp sẽ không tạo ra sự xáo trộn 'chính hãng'!
Christoph

@Christoph: Suy nghĩ về điều đó, ngay cả Fisher-Yates sẽ chỉ cung cấp một bản phân phối "hoàn hảo" nếu rand (x) được đảm bảo chính xác ngay cả trong phạm vi của nó. Vì thường có 2 ^ x trạng thái có thể có cho RNG cho một số x, tôi không nghĩ nó sẽ chính xác ngay cả đối với rand (3).
Jon Skeet

@Jon: nhưng Fisher-Yates sẽ tạo 2^xcác trạng thái cho từng chỉ số mảng, tức là sẽ có tổng số 2 ^ (xn) trạng thái, sẽ lớn hơn một chút so với 2 ^ c - xem câu trả lời được chỉnh sửa của tôi để biết chi tiết
Christoph

@Christoph: Tôi có thể không giải thích chính mình. Giả sử bạn chỉ có 3 yếu tố. Bạn chọn ngẫu nhiên phần tử đầu tiên, trong số tất cả 3. Để có phân phối đồng đều hoàn toàn , bạn phải có thể chọn một số ngẫu nhiên trong phạm vi [0,3) hoàn toàn đồng đều - và nếu PRNG có 2 ^ n trạng thái có thể, bạn không thể làm điều đó - một hoặc hai trong số các khả năng sẽ có xác suất xảy ra cao hơn một chút .
Jon Skeet

118

Sau khi Jon đã trình bày lý thuyết , đây là một triển khai:

function shuffle(array) {
    var tmp, current, top = array.length;

    if(top) while(--top) {
        current = Math.floor(Math.random() * (top + 1));
        tmp = array[current];
        array[current] = array[top];
        array[top] = tmp;
    }

    return array;
}

Các thuật toán là O(n), trong khi sắp xếp nên được O(n log n). Tùy thuộc vào chi phí thực thi mã JS so với sort()hàm gốc , điều này có thể dẫn đến sự khác biệt đáng chú ý về hiệu suất sẽ tăng theo kích thước mảng.


Trong các bình luận cho câu trả lời của bobobobo , tôi đã nói rằng thuật toán được đề cập có thể không tạo ra xác suất phân bố đồng đều (tùy thuộc vào việc thực hiện sort()).

Đối số của tôi đi dọc theo các dòng này: Một thuật toán sắp xếp yêu cầu một số cso sánh nhất định , ví dụ như c = n(n-1)/2đối với Bubbledort. Hàm so sánh ngẫu nhiên của chúng tôi làm cho kết quả của mỗi so sánh có khả năng như nhau, tức là có kết quả 2^c có thể xảy ra như nhau . Bây giờ, mỗi kết quả phải tương ứng với một trong các n!hoán vị của các mục của mảng, điều này làm cho phân phối chẵn không thể trong trường hợp chung. (Đây là một sự đơn giản hóa, vì số lượng so sánh thực tế được ghi nhận phụ thuộc vào mảng đầu vào, nhưng khẳng định vẫn nên giữ.)

Như Jon đã chỉ ra, điều này một mình không có lý do để thích sử dụng Fisher-Yates hơn sort(), vì trình tạo số ngẫu nhiên cũng sẽ ánh xạ một số hữu hạn các giá trị giả ngẫu nhiên vào các n!hoán vị. Nhưng kết quả của Fisher-Yates vẫn tốt hơn:

Math.random()tạo ra một số giả ngẫu nhiên trong phạm vi [0;1[. Vì JS sử dụng các giá trị dấu phẩy động có độ chính xác kép, nên giá trị này tương ứng với 2^xcác giá trị có thể có 52 ≤ x ≤ 63(Tôi quá lười để tìm số thực tế). Một phân phối xác suất được tạo bằng cách sử dụng Math.random()sẽ ngừng hoạt động tốt nếu số lượng các sự kiện nguyên tử có cùng độ lớn.

Khi sử dụng Fisher-Yates, tham số có liên quan là kích thước của mảng, không bao giờ nên tiếp cận 2^52do những hạn chế thực tế.

Khi sắp xếp với hàm so sánh ngẫu nhiên, về cơ bản, hàm chỉ quan tâm nếu giá trị trả về là dương hay âm, vì vậy điều này sẽ không bao giờ là vấn đề. Nhưng có một điều tương tự: Bởi vì chức năng so sánh được xử lý tốt, nên các 2^ckết quả có thể, như đã nêu, có thể xảy ra như nhau. Nếu c ~ n log nsau đó 2^c ~ n^(a·n)ở đâu a = const, điều đó làm cho nó ít nhất có thể có 2^ccùng độ lớn với (hoặc thậm chí nhỏ hơn) n!và do đó dẫn đến phân phối không đồng đều, ngay cả khi thuật toán sắp xếp nơi ánh xạ lên các hoán vị đồng đều. Nếu điều này có bất kỳ tác động thực tế là ngoài tôi.

Vấn đề thực sự là các thuật toán sắp xếp không được đảm bảo để ánh xạ lên các hoán vị đồng đều. Thật dễ dàng để thấy rằng Mergesort làm như đối xứng, nhưng lý do về một cái gì đó như Bubbledort hoặc quan trọng hơn, Quicksort hoặc Heapsort, thì không.


Điểm mấu chốt: Miễn là sort()sử dụng Mergesort, bạn nên an toàn một cách hợp lý trừ trường hợp góc (ít nhất là tôi hy vọng đó 2^c ≤ n!là trường hợp góc), nếu không, tất cả các cược đều bị tắt.


Cảm ơn đã thực hiện. Thật nhanh quá! Đặc biệt là so với cái tào lao chậm chạp mà tôi tự viết trong lúc đó.
Rene Saarsoo

1
Nếu bạn đang sử dụng thư viện underscore.js, đây là cách mở rộng nó bằng phương pháp xáo trộn Fisher-Yates ở trên: github.com/ryantenney/underscore/commit/ trộm
Steve

Cảm ơn bạn rất nhiều vì điều này, sự kết hợp giữa câu trả lời của bạn và John đã giúp tôi khắc phục một vấn đề mà tôi và một đồng nghiệp đã dành gần 4 giờ kết hợp! Ban đầu chúng tôi có một phương pháp tương tự như OP nhưng thấy rằng tính ngẫu nhiên rất dễ bị hỏng, vì vậy chúng tôi đã sử dụng phương pháp của bạn và thay đổi một chút để làm việc với một chút jquery để xáo trộn danh sách hình ảnh (cho một thanh trượt) để lấy một số ngẫu nhiên tuyệt vời.
Xin chào thế giới

16

Tôi đã thực hiện một số phép đo về mức độ ngẫu nhiên của kết quả của loại ngẫu nhiên này ...

Kỹ thuật của tôi là lấy một mảng nhỏ [1,2,3,4] và tạo ra tất cả (4! = 24) hoán vị của nó. Sau đó, tôi sẽ áp dụng hàm xáo trộn cho mảng một số lượng lớn thời gian và đếm xem mỗi lần hoán vị được tạo ra bao nhiêu lần. Một algoritm xáo trộn tốt sẽ phân phối kết quả khá đồng đều trên tất cả các hoán vị, trong khi một điều xấu sẽ không tạo ra kết quả thống nhất đó.

Sử dụng mã dưới đây tôi đã thử nghiệm trong Firefox, Opera, Chrome, IE6 / 7/8.

Đáng ngạc nhiên đối với tôi, cả hai loại ngẫu nhiên và xáo trộn thực sự đều tạo ra các bản phân phối đồng đều như nhau. Vì vậy, có vẻ như (như nhiều người đã đề xuất) các trình duyệt chính đang sử dụng sắp xếp hợp nhất. Tất nhiên điều này không có nghĩa là, không thể có một trình duyệt ngoài kia, điều đó khác, nhưng tôi sẽ nói nó có nghĩa là phương pháp sắp xếp ngẫu nhiên này đủ đáng tin cậy để sử dụng trong thực tế.

EDIT: Thử nghiệm này không thực sự đo lường chính xác tính ngẫu nhiên hoặc thiếu. Xem câu trả lời khác tôi đã đăng.

Nhưng về mặt hiệu suất, chức năng xáo trộn do Cristoph đưa ra là một chiến thắng rõ ràng. Ngay cả đối với các mảng bốn phần tử nhỏ, shuffle thực sự thực hiện nhanh gấp đôi so với sắp xếp ngẫu nhiên!

// Hàm xáo trộn được đăng bởi Cristoph.
var shuffle = function (mảng) {
    var tmp, hiện tại, top = mảng.length;

    if (top) while (- top) {
        hiện tại = Math.floor (Math.random () * (đầu + 1));
        tmp = mảng [hiện tại];
        mảng [hiện tại] = mảng [đầu];
        mảng [top] = tmp;
    }

    trả về mảng;
};

// hàm sắp xếp ngẫu nhiên
var rnd = function () {
  trả về Math.round (Math.random ()) - 0,5;
};
var randSort = function (A) {
  trả lại A.sort (rnd);
};

hoán vị var = hàm (A) {
  if (A.length == 1) {
    trả lại [A];
  }
  khác {
    var perms = [];
    for (var i = 0; i <A.length; i ++) {
      var x = A.slice (i, i + 1);
      var xs = A.slice (0, i) .concat (A.slice (i + 1));
      subperms var = hoán vị (xs);
      for (var j = 0; j <subperms.length; j ++) {
        perms.push (x.concat (subperms [j]));
      }
    }
    trở lại perms;
  }
};

var test = hàm (A, lặp, func) {
  // hoán vị
  thống kê var = {};
  var perms = hoán vị (A);
  for (var i in perms) {
    thống kê ["" + perms [i]] = 0;
  }

  // xáo trộn nhiều lần và thu thập số liệu thống kê
  var start = ngày mới ();
  for (var i = 0; i <iterations; i ++) {
    var xáo trộn = func (A);
    số liệu thống kê ["" + xáo trộn] ++;
  }
  var end = ngày mới ();

  // định dạng kết quả
  var mảng = [];
  cho (var i trong số liệu thống kê) {
    Array.push (i + "" + stats [i]);
  }
  return Array.join ("\ n") + "\ n \ nThời gian thực hiện:" + ((kết thúc - bắt đầu) / 1000) + "giây.";
};

cảnh báo ("sắp xếp ngẫu nhiên:" + kiểm tra ([1,2,3,4], 100000, randSort));
cảnh báo ("xáo trộn:" + kiểm tra ([1,2,3,4], 100000, xáo trộn));

11

Thật thú vị, Microsoft đã sử dụng kỹ thuật tương tự trong trang trình duyệt chọn ngẫu nhiên của họ.

Họ đã sử dụng một chức năng so sánh hơi khác nhau:

function RandomSort(a,b) {
    return (0.5 - Math.random());
}

Trông gần giống với tôi, nhưng hóa ra nó không quá ngẫu nhiên ...

Vì vậy, tôi đã thực hiện một số thử nghiệm một lần nữa với cùng một phương pháp được sử dụng trong bài viết được liên kết, và thực tế - hóa ra phương pháp phân loại ngẫu nhiên tạo ra kết quả thiếu sót. Mã kiểm tra mới tại đây:

function shuffle(arr) {
  arr.sort(function(a,b) {
    return (0.5 - Math.random());
  });
}

function shuffle2(arr) {
  arr.sort(function(a,b) {
    return (Math.round(Math.random())-0.5);
  });
}

function shuffle3(array) {
  var tmp, current, top = array.length;

  if(top) while(--top) {
    current = Math.floor(Math.random() * (top + 1));
    tmp = array[current];
    array[current] = array[top];
    array[top] = tmp;
  }

  return array;
}

var counts = [
  [0,0,0,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0],
  [0,0,0,0,0]
];

var arr;
for (var i=0; i<100000; i++) {
  arr = [0,1,2,3,4];
  shuffle3(arr);
  arr.forEach(function(x, i){ counts[x][i]++;});
}

alert(counts.map(function(a){return a.join(", ");}).join("\n"));

Tôi không thấy lý do tại sao nó phải là 0,5 - Math.random (), tại sao không chỉ là Math.random ()?
Alexander Mills

1
@AlexanderMills: Hàm so sánh được truyền vào sort()được cho là trả về một số lớn hơn, nhỏ hơn hoặc bằng 0 tùy thuộc vào so sánh ab. ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
mẹo

@LarsH vâng điều đó có ý nghĩa
Alexander Mills

9

Tôi đã đặt một trang thử nghiệm đơn giản trên trang web của mình cho thấy sự thiên vị của trình duyệt hiện tại của bạn so với các trình duyệt phổ biến khác sử dụng các phương pháp khác nhau để xáo trộn. Nó cho thấy sự thiên vị khủng khiếp của việc chỉ sử dụng Math.random()-0.5, một sự xáo trộn 'ngẫu nhiên' khác không thiên vị và phương pháp Fisher-Yates đã đề cập ở trên.

Bạn có thể thấy rằng trên một số trình duyệt có khả năng cao tới 50% rằng một số yếu tố nhất định sẽ không thay đổi vị trí nào trong quá trình 'xáo trộn'!

Lưu ý: bạn có thể thực hiện việc xáo trộn Fisher-Yates bằng @Christoph nhanh hơn một chút cho Safari bằng cách thay đổi mã thành:

function shuffle(array) {
  for (var tmp, cur, top=array.length; top--;){
    cur = (Math.random() * (top + 1)) << 0;
    tmp = array[cur]; array[cur] = array[top]; array[top] = tmp;
  }
  return array;
}

Kết quả kiểm tra: http://jsperf.com/optimized-fisher-yates


5

Tôi nghĩ sẽ tốt cho những trường hợp bạn không kén chọn phân phối và bạn muốn mã nguồn nhỏ.

Trong JavaScript (nơi nguồn được truyền liên tục), nhỏ tạo ra sự khác biệt về chi phí băng thông.


2
Điều quan trọng là, bạn hầu như luôn kén chọn phân phối hơn bạn nghĩ và đối với "mã nhỏ", luôn arr = arr.map(function(n){return [Math.random(),n]}).sort().map(function(n){return n[1]});có ưu điểm là không quá dài quá lâu và thực sự được phân phối hợp lý. Ngoài ra còn có các biến thể shuffle Knuth / FY rất nén.
Daniel Martin

@DanielMartin Đó là một câu trả lời. Ngoài ra, để tránh lỗi phân tích cú pháp, hai dấu chấm phẩy cần được thêm vào để nó trông như thế này:arr = arr.map(function(n){return [Math.random(),n];}).sort().map(function(n){return n[1];}); .
Giacomo1968

2

Đó là một hack, chắc chắn. Trong thực tế, một thuật toán lặp vô hạn không có khả năng. Nếu bạn đang sắp xếp các đối tượng, bạn có thể lặp qua mảng coords và làm một cái gì đó như:

for (var i = 0; i < coords.length; i++)
    coords[i].sortValue = Math.random();

coords.sort(useSortValue)

function useSortValue(a, b)
{
  return a.sortValue - b.sortValue;
}

(và sau đó lặp lại chúng một lần nữa để loại bỏ sortValue)

Vẫn là một hack mặc dù. Nếu bạn muốn làm điều đó một cách độc đáo, bạn phải làm điều đó một cách khó khăn :)


2

Đã bốn năm, nhưng tôi muốn chỉ ra rằng phương pháp so sánh ngẫu nhiên sẽ không được phân phối chính xác, bất kể bạn sử dụng thuật toán sắp xếp nào.

Bằng chứng:

  1. Đối với một mảng các nphần tử, có các n!hoán vị chính xác (nghĩa là có thể xáo trộn).
  2. Mỗi so sánh trong một shuffle là một sự lựa chọn giữa hai bộ hoán vị. Đối với một bộ so sánh ngẫu nhiên, có 1/2 cơ hội chọn mỗi bộ.
  3. Do đó, với mỗi hoán vị p, cơ hội kết thúc với hoán vị p là một phân số có mẫu số 2 ^ k (đối với một số k), bởi vì nó là tổng của các phân số như vậy (ví dụ: 1/8 + 1/16 = 3/16 ).
  4. Với n = 3, có sáu hoán vị có khả năng như nhau. Cơ hội của mỗi hoán vị, sau đó, là 1/6. 1/6 không thể được biểu thị dưới dạng phân số có lũy thừa bằng 2 như mẫu số của nó.
  5. Do đó, loại lật đồng xu sẽ không bao giờ dẫn đến sự phân phối công bằng của xáo trộn.

Các kích thước duy nhất có thể được phân phối chính xác là n = 0,1,2.


Như một bài tập, hãy thử vẽ cây quyết định của các thuật toán sắp xếp khác nhau cho n = 3.


Có một lỗ hổng trong bằng chứng: Nếu một thuật toán sắp xếp phụ thuộc vào tính nhất quán của bộ so sánh và có thời gian chạy không giới hạn với bộ so sánh không nhất quán, nó có thể có tổng xác suất vô hạn, được phép thêm tới 1/6 ngay cả khi mỗi mẫu số trong tổng là một lũy thừa của 2. Hãy cố gắng tìm một mẫu số.

Ngoài ra, nếu một bộ so sánh có cơ hội cố định đưa ra một trong hai câu trả lời (ví dụ: (Math.random() < P)*2 - 1không đổi P), thì bằng chứng trên giữ vững. Nếu bộ so sánh thay đổi tỷ lệ cược dựa trên các câu trả lời trước đó, có thể tạo ra kết quả công bằng. Tìm một bộ so sánh như vậy cho một thuật toán sắp xếp nhất định có thể là một bài nghiên cứu.


1

Nếu bạn đang sử dụng D3, có chức năng xáo trộn tích hợp (sử dụng Fisher-Yates):

var days = ['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche'];
d3.shuffle(days);

Và đây là Mike đi sâu vào chi tiết về nó:

http://bost.ocks.org/mike/shuffle/


0

Đây là một cách tiếp cận sử dụng một mảng duy nhất:

Logic cơ bản là:

  • Bắt đầu với một mảng gồm n phần tử
  • Xóa một phần tử ngẫu nhiên khỏi mảng và đẩy nó vào mảng
  • Xóa một phần tử ngẫu nhiên khỏi n - 1 phần tử đầu tiên của mảng và đẩy nó vào mảng
  • Xóa một phần tử ngẫu nhiên khỏi n - 2 phần tử đầu tiên của mảng và đẩy nó vào mảng
  • ...
  • Loại bỏ phần tử đầu tiên của mảng và đẩy nó vào mảng
  • Mã số:

    for(i=a.length;i--;) a.push(a.splice(Math.floor(Math.random() * (i + 1)),1)[0]);

    Việc triển khai của bạn có rủi ro cao khi để một số lượng đáng kể các yếu tố chưa được xử lý. Chúng sẽ chỉ được thay đổi trong toàn bộ mảng bởi số lượng phần tử kém hơn đã được đẩy lên hàng đầu. Có một mô hình được vẽ trong sự xáo trộn đó làm cho nó không đáng tin cậy.
    Kir Kanos

    @KirKanos, tôi không chắc là tôi hiểu bình luận của bạn. Giải pháp tôi đề xuất là O (n). Nó chắc chắn sẽ "chạm" vào mọi yếu tố. Đây là một bí ẩn để chứng minh.
    ic3b3rg

    0

    Bạn có thể sử dụng Array.sort()chức năng để xáo trộn một mảng - Có.

    Là kết quả đủ ngẫu nhiên - Không.

    Hãy xem xét đoạn mã sau:

    var array = ["a", "b", "c", "d", "e"];
    var stats = {};
    array.forEach(function(v) {
      stats[v] = Array(array.length).fill(0);
    });
    //stats = {
    //    a: [0, 0, 0, ...]
    //    b: [0, 0, 0, ...]
    //    c: [0, 0, 0, ...]
    //    ...
    //    ...
    //}
    var i, clone;
    for (i = 0; i < 100; i++) {
      clone = array.slice(0);
      clone.sort(function() {
        return Math.random() - 0.5;
      });
      clone.forEach(function(v, i) {
        stats[v][i]++;
      });
    }
    
    Object.keys(stats).forEach(function(v, i) {
      console.log(v + ": [" + stats[v].join(", ") + "]");
    })

    Đầu ra mẫu:

    a [29, 38, 20,  6,  7]
    b [29, 33, 22, 11,  5]
    c [17, 14, 32, 17, 20]
    d [16,  9, 17, 35, 23]
    e [ 9,  6,  9, 31, 45]

    Lý tưởng nhất là tổng số phải được phân bổ đều (ví dụ trên, tất cả các tổng số nên ở khoảng 20). Nhưng họ thì không. Rõ ràng, phân phối phụ thuộc vào thuật toán sắp xếp nào được trình duyệt triển khai và cách nó lặp lại các mục mảng để sắp xếp.

    Thông tin chi tiết hơn được cung cấp trong bài viết này:
    Không nên sử dụng Array.sort () để xáo trộn một mảng


    -3

    Không có gì là sai với nó.

    Hàm bạn truyền cho .sort () thường trông giống như

    chức năng sắp xếpFunc (thứ nhất, thứ hai)
    {
      // thí dụ:
      trở lại đầu tiên - thứ hai;
    }
    

    Công việc của bạn trong sortingFunc là trả về:

    • một số âm nếu đầu tiên đi trước thứ hai
    • một số dương nếu trước tiên nên đi sau thứ hai
    • và 0 nếu chúng hoàn toàn bằng nhau

    Các chức năng sắp xếp ở trên đặt mọi thứ theo thứ tự.

    Nếu bạn trả lại ngẫu nhiên và + là những gì bạn có, bạn sẽ nhận được một thứ tự ngẫu nhiên.

    Giống như trong MySQL:

    CHỌN * từ bảng ĐẶT HÀNG THEO rand ()
    

    5
    một cái gì đó sai trái với phương pháp này: tùy thuộc vào các thuật toán sắp xếp được sử dụng bởi việc thực hiện JS, xác suất sẽ không được chia đều!
    Christoph

    Đó có phải là điều chúng ta thực sự lo lắng?
    bobobobo

    4
    @bobobobo: tùy thuộc vào ứng dụng, vâng, đôi khi chúng tôi làm; Ngoài ra, một hoạt động chính xácshuffle() chỉ phải được viết một lần, vì vậy nó không thực sự là vấn đề: chỉ cần đặt đoạn mã vào kho mã của bạn và khai quật nó bất cứ khi nào bạn cần
    Christoph
    Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
    Licensed under cc by-sa 3.0 with attribution required.