> pick | shuffle | pair <
// الصق قائمة، واختر الفائزين، أو امزج الترتيب، أو وزّع الأشخاص إلى مجموعات - كل ذلك داخل متصفحك
اختر N عنصرًا عشوائيًا
اسحب أي عدد من الفائزين من قائمتك. بدون إرجاع للحصول على فائزين فريدين، أو مع الإرجاع لإجراء سحوبات بأسلوب مرجّح.
مزج فيشر-ييتس غير المتحيّز
يعيد ترتيب القائمة بالكامل باستخدام مزج كنوث الكلاسيكي. كل تبديلة محتملة بالتساوي - لا حيل فرز ساذجة هنا.
التوزيع إلى مجموعات
قسّم القائمة إلى أزواج أو ثلاثيات أو أي حجم مجموعة. مثالي للعمل بالشراكة، وتناوب مراجعة الشيفرة، وتكوين أزواج بابا نويل السري.
قابلية إعادة الإنتاج بالبذرة
قدّم سلسلة بذرة للحصول على سحب حتمي. البذرة نفسها مع القائمة نفسها تنتج دائمًا النتيجة نفسها - قابلة للمشاركة والتحقق.
// حول أداة الاختيار العشوائي
كيف تعمل:
تستخدم هذه الأداة مزج فيشر-ييتس (المعروف أيضًا بمزج كنوث): اجتَز المصفوفة من آخر فهرس إلى الأول، وفي كل خطوة بدّل العنصر الحالي بعنصر عند فهرس سابق مُختار عشوائيًا بانتظام. ينتج عن ذلك تبديلة منتظمة وغير متحيّزة في زمن O(n). الحيلة الساذجة array.sort(() => Math.random() - 0.5) متحيّزة لأن مقارِنات الفرز في JavaScript يجب أن تكون متعدّية - المقارِنات العشوائية تنتهك ذلك وتشوّه التوزيع. للسحوبات بدون بذرة نأخذ الإنتروبيا من window.crypto.getRandomValues. وعندما تقدّم سلسلة بذرة، نحسب تجزئتها باستخدام cyrb53 إلى عدد صحيح بطول 53 بت، ثم نشغّل مولّد الأعداد شبه العشوائية mulberry32 بحيث تنتج البذور المتطابقة نتائج متطابقة وقابلة لإعادة الإنتاج.
الخوارزمية:
for i = n-1 down to 1: j = randInt(0, i); swap(a[i], a[j]) - unbiased Fisher-Yates
المعايير والمراجع:
- >Web Crypto API (W3C) - crypto.getRandomValues لعشوائية قوية تشفيريًا
- >مزج فيشر-ييتس (1938)، الذي شاع بفضل دونالد كنوث في The Art of Computer Programming المجلد 2
- >mulberry32 - مولّد أعداد شبه عشوائية صغير وسريع وجيد التوزيع من تأليف Tommy Ettinger
- >cyrb53 - تجزئة سلسلة بطول 53 بت من تأليف bryc، تُستخدم لتحويل سلسلة البذرة إلى حالة عددية لمولّد الأعداد شبه العشوائية
حالات الاستخدام الشائعة:
- >الهدايا والسحوبات وتسمية فائز عشوائي من بين المشاركات
- >سحب الأسماء في الفصل الدراسي واختيار الطلاب للإجابة المفاجئة
- >تكوين أزواج الفرق الرياضية، وتمارين الشراكة، وجداول البطولات
- >إسناد مراجِعي الشيفرة عبر فريق هندسي
- >اختيار عينة اختبار A/B ومجموعات الاستبيان المعشّاة
- >أزواج بابا نويل السري، وتبادل الهدايا، ورفقاء غداء الفريق
- >مدخلات اختبار عشوائية وبذور تشويش (fuzzing) لضمان الجودة
- >اتخاذ القرارات الجماعية وكسر التعادل
- >اختيار هيئة محلفين صورية ولجان مقابلات معشّاة
- >سحوبات على غرار اليانصيب لفعاليات المجتمع والجوائز
أدوات ذات صلة:
- >مولّد الأرقام العشوائية — الرفيق النصّي: اختر أرقامًا ضمن نطاق بنفس مبادئ قابلية إعادة الإنتاج بالبذرة
- >مولّد UUID — معرّفات v4 عشوائية عندما تحتاج إلى معرّف فريد مبهم بدلًا من فائز من قائمة
- >مولّد كلمات المرور — سلاسل عشوائية تشفيريًا مع التحكم في مجموعة الأحرف للرموز وبيانات الاعتماد
- >randompickerwheel.app — واجهة عجلة دوّارة مكمّلة لأداة الاختيار النصّية هذه، مثالية للسحوبات أمام جمهور مباشر، والنداء في الفصل، والكشف على الشاشة
// أمثلة على الاختيار
هدية — اختر 3 فائزين من 50 مشاركة
> input:
alice@x.com
bob@x.com
carlos@x.com
…(50 سطرًا في المجموع)
> config:
الوضع=Pick N, العدد=3, السماح بالتكرار=off, البذرة=(فارغة)
> output:
1. carlos@x.com
2. priya@x.com
3. wei@x.com
امزج قائمة من 10 أسماء لترتيب عرض تقديمي
> input:
Alice
Bob
Charlie
Dana
Evelyn
Farouk
Gabriela
Hiroshi
Isabella
Jamal
> config:
الوضع=Shuffle, البذرة=(فارغة)
> output:
1. Hiroshi
2. Alice
3. Farouk
4. Jamal
5. Dana
6. Evelyn
7. Bob
8. Isabella
9. Gabriela
10. Charlie
وزّع فصلًا من 12 طالبًا إلى مجموعات من اثنين
> input:
S01
S02
S03
S04
S05
S06
S07
S08
S09
S10
S11
S12
> config:
الوضع=Pair Up, حجم المجموعة=2, البذرة=class-2026-05-02
> output:
مجموعة 1: S07, S02
مجموعة 2: S11, S04
مجموعة 3: S09, S12
مجموعة 4: S01, S06
مجموعة 5: S03, S10
مجموعة 6: S08, S05
سحب قابل لإعادة الإنتاج بالبذرة — شغّله مرتين بنفس البذرة لتحصل على نفس الفائزين
> input:
alpha
bravo
charlie
delta
echo
foxtrot
golf
hotel
> config:
الوضع=Pick N, العدد=2, البذرة=launch-day, السماح بالتكرار=off
> output:
التشغيل 1: 1. echo
2. bravo
التشغيل 2: 1. echo
2. bravo (متطابق — بالبذرة)
// لماذا يكون .SORT() الساذج متحيّزًا
أحد أكثر أساليب المزج شيوعًا في سطر واحد هو arr.sort(() => Math.random() - 0.5). يبدو أنيقًا، ويُكتب في سطر واحد، ويُشعِر بالعشوائية — لكن توزيع التبديلات الناتج بعيد كل البعد عن الانتظام. تشترط مواصفة ECMAScript أن تكون دوال المقارنة حتمية ومتعدّية: إذا كان a < b و b < c، فإن a < c. مقارِن "الصورة أو الكتابة" ينتهك هذا العقد، وتزور خوارزمية الفرز في المحرك أزواج المقارنة بنمط غير منتظم.
يستخدم V8 (Chrome، Node) خوارزمية Timsort؛ بينما استخدمت المحركات الأقدم quicksort أو mergesort. تزور كل خوارزمية مجموعة فرعية مختلفة من أزواج المقارنة وتعيد استخدام المقارنات المخزّنة مؤقتًا بطرق مختلفة. وكما أوضح Mike Bostock تجريبيًا (bost.ocks.org/mike/shuffle/compare.html)، فإن الفرز الساذج ينتج مخرجات شديدة التحيّز تظهر فيها بعض التبديلات بمعدل أكبر بعدة مرات من غيرها — وهو أمر غير مقبول لهدية أو سلة A/B أو أي سحب يجب أن يكون عادلًا.
الخوارزمية الصحيحة هي فيشر-ييتس (مزج كنوث): اجتَز المصفوفة من آخر فهرس وصولًا إلى الأول، وفي كل خطوة بدّل العنصر الحالي بعنصر مُختار عشوائيًا بانتظام من بين الفهارس 0..i. تعمل في زمن O(n)، وتستخدم مساحة إضافية O(1)، ويمكن إثبات أنها تنتج كل تبديلة باحتمال متساوٍ.
// BAD: NOT uniformly random
const shuffled = arr.sort(() => Math.random() - 0.5);
// GOOD: Fisher-Yates (Knuth) shuffle
function shuffle(arr) {
const a = arr.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
// نفّذها بنفسك
هل تريد بناء أداة الاختيار الخاصة بك، أو تدقيق أداتنا؟ هذه هي المكوّنات الأساسية ذاتها التي تستخدمها هذه الصفحة — صغيرة، وخالية من التبعيات، ومطابقة لما يعمل في متصفحك عند النقر على PICK. انسخها مباشرة إلى نص برمجي بلغة Node أو إلى تطبيق ويب آخر.
// Fisher-Yates shuffle (uniform, O(n))
function shuffle(arr, rng = Math.random) {
const a = arr.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(rng() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
// Pick N without replacement (shuffle then slice)
function pickN(arr, n, rng = Math.random) {
if (n > arr.length) {
throw new Error('n exceeds list size');
}
return shuffle(arr, rng).slice(0, n);
}
// mulberry32 seeded PRNG + cyrb53 string hash
// cyrb53: turn a seed string into a 53-bit integer
function cyrb53(str, seed = 0) {
let h1 = 0xdeadbeef ^ seed;
let h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
}
// mulberry32: tiny seeded PRNG -> [0, 1)
function mulberry32(a) {
return function () {
a |= 0; a = (a + 0x6D2B79F5) | 0;
let t = a;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// Build a seeded picker:
const h = cyrb53('my-seed', 1);
const state = (h ^ Math.floor(h / 4294967296)) >>> 0;
const rng = mulberry32(state);
const winners = pickN(['alice', 'bob', 'carlos'], 2, rng);
>> الأسئلة الشائعة
س: كيف يتم توليد العشوائية؟
ج: عند عدم تقديم بذرة، نستخدم window.crypto.getRandomValues، وهو مولّد الأرقام العشوائية الآمن تشفيريًا في المتصفح والمعتمد على Web Crypto API. وهو نفس مصدر الإنتروبيا المستخدم للمفاتيح والرموز التشفيرية، لذا فهو أقوى بكثير مما تحتاجه السحوبات وعمليات المزج. وعندما تقدّم بذرة، نشتق حتميًا حالة بطول 53 بت عبر تجزئة السلسلة cyrb53 ونغذّيها إلى مولّد mulberry32 بحيث يكون السحب قابلًا لإعادة الإنتاج.
س: هل يمكنني الحصول على النتيجة نفسها مرتين باستخدام بذرة؟
ج: نعم. اكتب أي سلسلة في حقل SEED - تاريخ، أو اسم مسابقة، أو تجزئة، أو أي شيء. ستنتج البذرة نفسها مع قائمة الإدخال نفسها والوضع نفسه دائمًا المخرجات ذاتها بالضبط. هذا أمر بالغ القيمة للهدايا الشفافة التي ترغب فيها بنشر البذرة مسبقًا والسماح للمشاركين بالتحقق من السحب، أو لتناوبات الهندسة التي يجب أن تكون قابلة لإعادة الإنتاج عبر الأجهزة.
س: ما الفرق بين Pick N و Shuffle؟
ج: يختار Pick N مجموعة فرعية بحجم N من قائمتك، اختياريًا مع الإرجاع (التكرار مسموح). أما Shuffle فيعيد القائمة بأكملها بترتيب جديد - لا تُحذف أي عناصر ولا تتكرر، بل تُعاد ترتيبها فقط. استخدم Pick N عندما تريد بضعة فائزين فقط من بين العديد من المشاركات؛ واستخدم Shuffle عندما يجب أن يظل كل عنصر مشاركًا ولكن بترتيب عشوائي جديد، مثل طابور عرض تقديمي أو قائمة تشغيل.
س: هل array.sort(() => Math.random() - 0.5) عشوائي حقًا؟
ج: لا، إنه متحيّز. تشترط مواصفة ECMAScript أن تكون مقارِنات الفرز حتمية ومتعدّية (إذا كان a < b و b < c فإن a < c). المقارِن العشوائي ينتهك هذا العقد، كما تشغّل محركات JavaScript المختلفة خوارزميات فرز أساسية مختلفة (TimSort وmergesort وquicksort) تتفاعل مع المقارِن العشوائي بطرق مختلفة. والنتيجة توزيع غير منتظم تظهر فيه بعض التبديلات بمعدل أكبر بكثير من غيرها. فيشر-ييتس هو الخوارزمية الصحيحة.
س: هل يمكنني تكوين أزواج من قائمة ذات عدد فردي؟
ج: نعم. يمزج وضع Pair Up قائمتك باستخدام فيشر-ييتس ثم يقسّمها وفق حجم المجموعة الذي تختاره. وإذا لم يكن المجموع قابلًا للقسمة بالتساوي، فستكون المجموعة الأخيرة أصغر وتُوسَم بوضوح كمجموعة متبقية في المخرجات. وفي القائمة الفردية يمكنك إما قبول مدخل منفرد، أو زيادة حجم المجموعة، أو إضافة اسم نائب مثل "bye" قبل السحب.
س: هل تُرفع قائمتي إلى أي مكان؟
ج: لا. هذه الأداة تعمل بنسبة 100% من جانب العميل - فقائمتك وبذرتك والمخرجات لا تغادر متصفحك أبدًا. لا يوجد أي استدعاء للخادم، ولا تسجيل، ولا أي تحليلات على الإدخال. يمكنك قطع الاتصال بالإنترنت بعد تحميل الصفحة وستظل كل الأزرار تعمل. حدّث الصفحة وستختفي البيانات إلى الأبد.
س: هل توجد نسخة مرئية بعجلة دوّارة من هذه الأداة؟
ج: للحصول على تجربة عجلة أسماء تفاعلية مع رسوم متحركة ومؤثرات صوتية وكشف مرئي كبير، راجع randompickerwheel.app. إنه منتج مكمّل يركّز على السحوبات أمام جمهور مباشر ومشاركة الشاشة. هذه الصفحة هي أداة اختيار نصّية أولًا تركّز على القوائم الكبيرة والسحوبات القابلة لإعادة الإنتاج بالبذرة وتصدير CSV وتكوين الأزواج - وهي مفيدة عندما تحتاج إلى إجابة حتمية سريعة بدلًا من عرض تقديمي.