รับค่าสุ่มจากอาร์เรย์ JavaScript


794

พิจารณา:

var myArray = ['January', 'February', 'March'];    

ฉันจะเลือกค่าสุ่มจากอาร์เรย์นี้โดยใช้ JavaScript ได้อย่างไร

คำตอบ:


1481

มันเป็นหนึ่งซับง่าย

const randomElement = array[Math.floor(Math.random() * array.length)];

ตัวอย่าง

const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const randomMonth = months[Math.floor(Math.random() * months.length)];

console.log("random month =>", randomMonth);


9
@SapphireSun นี่ถูกต้อง หมายเหตุการMath.floor(Math.random(...))โทรซึ่งปัดเศษลง
ashes999

33
อ่าฉันได้เรียนรู้สิ่งใหม่แล้ว ฉันกำลังพูดถึงกรณีที่มันตรงกับที่ 1 แต่เห็นได้ชัดว่า (ตาม W3Schools) Math.random อยู่ระหว่าง 0 รวมและ 1 พิเศษ ความผิดฉันเอง.
SapphireSun

13
ฉันอาจจะผิด แต่ฉันจำได้ว่าvar rand = myArray[Math.random() * myArray.length>>0]เป็นเร็วขึ้นเล็กน้อย
vrugtehagel

6
ในกรณีที่ถ้าคุณใช้ lodash อยู่แล้วคุณสามารถใช้ _.sample (array) ได้
Gabriel Matusevich

2
ฉันชอบตัวแปรนี้:var rand = myArray[Math.random() * myArray.length | 0]
นิโคลัส

76

หากคุณมีอยู่แล้วขีดหรือlodash_.sampleรวมอยู่ในโครงการของคุณคุณสามารถใช้

// will return one item randomly from the array
_.sample(['January', 'February', 'March']);

หากคุณต้องการได้รับมากกว่าหนึ่งรายการแบบสุ่มคุณสามารถผ่านสิ่งนั้นเป็นอาร์กิวเมนต์ที่สองในการขีดเส้นใต้:

// will return two items randomly from the array using underscore
_.sample(['January', 'February', 'March'], 2);

หรือใช้_.sampleSizeวิธีใน lodash:

// will return two items randomly from the array using lodash
_.sampleSize(['January', 'February', 'March'], 2);

เมื่อใช้ typescript: โปรดทราบว่าประเภทการส่งคืนจะเป็น "string | undefined" แทน "string" ที่กำหนดให้กับอาร์เรย์สตริง
Stephan Schielke

23

วิธีการต้นแบบ

หากคุณวางแผนที่จะรับค่าสุ่มจำนวนมากคุณอาจต้องการกำหนดฟังก์ชั่นให้

ก่อนอื่นให้ใส่รหัสของคุณลงในที่อื่น:

Array.prototype.sample = function(){
  return this[Math.floor(Math.random()*this.length)];
}

ขณะนี้:

[1,2,3,4].sample() //=> a random element

รหัสการปล่อยตัวในโดเมนสาธารณะภายใต้เงื่อนไขของมอนส์ CC0 1.0 ใบอนุญาต


และนี่จะทำอะไร
เคนคม

3
@KenSharp ช่วยให้คุณสามารถโทรหา.sample()อาเรย์ใดก็ได้เพื่อรับไอเทมสุ่ม
Ben Aubin

5
ควรหลีกเลี่ยงการขยายประเภทวัตถุเนทิฟ ฉันได้ลบคำตอบของฉันเพราะเห็นว่ามีผู้โหวตมาก แต่ก็ส่งเสริมการปฏิบัติที่ไม่ดี สำหรับการอภิปรายเพิ่มเติมเกี่ยวกับปัญหานี้ดูเช่นstackoverflow.com/questions/14034180/…และeslint.org/docs/rules/no-extend-native
Markus Amalthea Magnuson

20

~~เร็วกว่าMath.Floor()มากดังนั้นเมื่อพูดถึงการเพิ่มประสิทธิภาพในขณะที่สร้างผลผลิตโดยใช้องค์ประกอบ UI ~~จะทำให้เกมชนะ ข้อมูลเพิ่มเติม

var rand = myArray[~~(Math.random() * myArray.length)];

แต่ถ้าคุณรู้ว่าอาเรย์จะมีองค์ประกอบนับล้านกว่าที่คุณอาจต้องการพิจารณาใหม่ระหว่าง Bitwise Operator และMath.Floor()เนื่องจากโอเปอเรเตอร์ Bitwise มีพฤติกรรมแปลก ๆ กับตัวเลขจำนวนมาก ดูตัวอย่างด้านล่างอธิบายด้วยผลลัพธ์ ข้อมูลเพิ่มเติม

var number = Math.floor(14444323231.2); // => 14444323231
var number = 14444323231.2 | 0; // => 1559421343

1
การเชื่อมโยงจะตายโพสต์ที่น่าสนใจ แต่ฉันจะใช้มากกว่าMath.floorนี้ในขณะนี้ :)
24419

ใช้โอเปอเรเตอร์ "bitwise not" ในขณะที่เร็วกว่าไม่สามารถอ่านได้ดังนั้นคุณต้องเลือกสิ่งที่สำคัญสำหรับคุณ
Maciej Urbański

16

สมมติว่าคุณต้องการเลือกรายการแบบสุ่มที่แตกต่างจากครั้งที่แล้ว (ไม่ใช่แบบสุ่มจริงๆ แต่ยังเป็นข้อกำหนดทั่วไป) ...

จากคำตอบของ @Markus เราสามารถเพิ่มฟังก์ชั่นต้นแบบอื่นได้:

Array.prototype.randomDiffElement = function(last) {
   if (this.length == 0) {
      return;
   } else if (this.length == 1) {
      return this[0];
   } else {
      var num = 0;
      do {
         num = Math.floor(Math.random() * this.length);
      } while (this[num] == last);
      return this[num];
   }
}

และใช้งานเช่นนั้น:

var myRandomDiffElement = myArray.randomDiffElement(lastRandomElement)

11

หากคุณมีค่าคงที่ (เช่นรายชื่อเดือน) และต้องการโซลูชันบรรทัดเดียว

var result = ['January', 'February', 'March'][Math.floor(Math.random() * 3)]

ส่วนที่สองของอาร์เรย์คือการดำเนินการเข้าถึงตามที่อธิบายไว้ในเหตุใด [5,6,8,7] [1,2] = 8 ใน JavaScript


2
รหัสดังกล่าวเป็นการปฏิบัติที่ไม่ดีและเป็นอันตราย ไม่ควรใช้ในการผลิต มันมีความสามารถในการอ่านต่ำและมีความยาวของอาเรย์ฮาร์ดโค้ด คนที่เปลี่ยนอินพุตอาเรย์อาจลืมแก้ไขความยาวฮาร์ดโค้ดในที่สุด
Seagull

@Seagull OP ไม่เคยถามถึงสภาพแวดล้อมที่เฉพาะเจาะจง นอกจากนี้ความคิดเห็นนี้ไม่มีความหมายเนื่องจากสามารถนำไปใช้กับคำตอบเกือบทั้งหมดในคำถามนี้)
IG Pascual

แต่คนส่วนใหญ่มาถึงคำถามนี้จากการค้นหาของ Google และอาจใช้วิธีแก้ปัญหาในสถานการณ์อื่น ๆ นอกเหนือจาก OP ดั้งเดิม
Seagull

@Seagull ฮ่าฮ่าคนมีอิสระที่จะตัดสินใจว่าจะใช้วิธีไหนฉันไม่ได้เป็นคนสะอาดรหัสแนวทางคำถาม!
IG Pascual

10

รุ่นที่สั้นที่สุด:

var myArray = ['January', 'February', 'March']; 
var rand = myArray[(Math.random() * myArray.length) | 0]

อะไร| 0ทำอย่างไร
เคนคม

2
มันจะเปลี่ยนเป็น Float เป็น Int เช่นเดียวกับ Math.floor
foxiris

4
@KenSharp | 0ตัวเองคือการดำเนินการระดับบิตที่ไม่ทำอะไรเลย แต่ในลอยจาวาสคริปต์จะถูกแปลงเป็น ints ก่อนที่จะดำเนินการใด ดังนั้นมันจึงเป็นวิธีที่+ ''ไม่ได้ทำอะไรจริงๆ แต่สามารถใช้ในการแปลงสิ่งต่าง ๆ เป็นสาย
dshepherd

มันไม่เหมือนกันMath.floorแต่เป็นสิ่งที่ถูกต้องที่จะทำที่นี่ มันเป็นโอเปอเรเตอร์ดังนั้นจึงเร็วกว่าMath.floorถ้าเพียงเพราะเมื่อใดก็ตามที่ใช้รหัสบางอย่างสามารถทำได้Math.floor = someOtherFunctionและพวกเขาไม่สามารถทำเช่นเดียวกันสำหรับ '|' ในทางตรงกันข้ามกับการMath.floorและ|เป็นที่แตกต่างกันลองเทียบกับMath.floor(-1.5) -1.5 | 0โดยที่คุณไม่จำเป็นต้องใช้วงเล็บ |มีลำดับความสำคัญต่ำมาก
gman

7

หากคุณต้องการเขียนลงในหนึ่งบรรทัดเช่นโซลูชันของ Pascual โซลูชันอื่นจะเขียนโดยใช้ฟังก์ชั่น find ของ ES6 (ตามข้อเท็จจริงแล้วความน่าจะเป็นที่จะสุ่มเลือกรายการหนึ่งจากnนั้นคือ1/n):

var item = ['A', 'B', 'C', 'D'].find((_, i, ar) => Math.random() < 1 / (ar.length - i));
console.log(item);

ใช้วิธีการนั้นเพื่อการทดสอบและหากมีเหตุผลที่ดีที่จะไม่บันทึกอาเรย์ในตัวแปรแยกต่างหากเท่านั้น มิฉะนั้นคำตอบอื่น ๆ ( floor(random()*lengthและการใช้ฟังก์ชั่นแยก) เป็นวิธีของคุณไป


ทางออกที่เป็นต้นฉบับมาก เยี่ยมมาก! โดยวิธีการแก้ปัญหาหนึ่งซับจริงและแบบไดนามิกเดียวที่นี่
Slavik Meltser

7

Faker.jsมีฟังก์ชั่นยูทิลิตี้มากมายสำหรับการสร้างข้อมูลทดสอบแบบสุ่ม เป็นตัวเลือกที่ดีในบริบทของชุดทดสอบ:

const Faker = require('faker');
Faker.random.arrayElement(['January', 'February', 'March']);

ตามที่ผู้แสดงความคิดเห็นได้กล่าวถึงโดยทั่วไปคุณไม่ควรใช้ไลบรารีนี้ในรหัสการผลิต


8
สำหรับปัญหาง่ายๆเช่นนี้การเพิ่มการพึ่งพาสำหรับทั้งไลบรารีนั้นไม่จำเป็นและเพิ่มการขยายโค้ด หากมีสิ่งใดคุณอาจแนะนำวิธีการจริงFakerที่เลือกองค์ประกอบอาเรย์แบบสุ่ม
Pixxl

1
"ปัญหาง่าย ๆ " เช่นนี้มักจะได้รับการแก้ไขโดยห้องสมุดที่ให้วิธีการแก้ไขปัญหาที่คนหลายร้อยต้องเผชิญด้วย ห้องสมุดเหล่านี้มักจะมีความแข็งแกร่งและดีบั๊กและมีข้อตกลงกับคำเตือนต่าง ๆ ที่เราไม่ต้องการนำมาใช้ใหม่ โดยทั่วไปจะเป็นสถานการณ์ที่ฉันอยากจะแนะนำให้ใช้ห้องสมุด
smonff

กว่าคุณควรคัดลอกวิธีหนึ่งจากไลบรารีและวางไว้ในไฟล์ utils
Rick Bross

คำแนะนำที่ห้องสมุดควรได้รับการประเมินสำหรับค่าใช้จ่าย / ผลประโยชน์น้ำหนักหน้า WRT เมื่อจัดส่งไปยังเว็บเบราว์เซอร์เป็นคำแนะนำที่ถูกต้องและฉันเห็นด้วยอย่างจริงใจว่าการจัดส่ง Faker.js ไปยังเบราว์เซอร์ อย่างไรก็ตามคำถามไม่ได้กล่าวถึงการใช้งานรันไทม์ของ JS สำหรับการพึ่งพารันไทม์ที่หนักกว่า NodeJS นั้นเหมาะสมอย่างยิ่งซึ่งเป็นกรณีที่ฉันใช้ Faker.js - ในชุดทดสอบ Cucumber JS
นาธาน

6

การแก้ไข Array prototype อาจเป็นอันตรายได้ นี่คือฟังก์ชั่นง่าย ๆ ในการทำงาน

function getArrayRandomElement (arr) {
  if (arr && arr.length) {
    return arr[Math.floor(Math.random() * arr.length)];
  }
  // The undefined will be returned if the empty array was passed
}

การใช้งาน:

// Example 1
var item = getArrayRandomElement(['January', 'February', 'March']);

// Example 2
var myArray = ['January', 'February', 'March'];
var item = getArrayRandomElement(myArray);

3

ฟังก์ชั่นแบบเรียกซ้ำแบบสแตนด์อโลนซึ่งสามารถส่งคืนจำนวนรายการใด ๆ (เหมือนกับlodash.sampleSize ):

function getRandomElementsFromArray(array, numberOfRandomElementsToExtract = 1) {
    const elements = [];

    function getRandomElement(arr) {
        if (elements.length < numberOfRandomElementsToExtract) {
            const index = Math.floor(Math.random() * arr.length)
            const element = arr.splice(index, 1)[0];

            elements.push(element)

            return getRandomElement(arr)
        } else {
            return elements
        }
    }

    return getRandomElement([...array])
}

2

ที่จะได้รับ อาร์เรย์ของไอเท็มแบบสุ่มที่มีการเข้ารหัสที่แข็งแกร่ง

let rndItem = a=> a[rnd()*a.length|0];
let rnd = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

var myArray = ['January', 'February', 'March'];

console.log( rndItem(myArray) )


1

สิ่งนี้คล้ายกับ แต่เหนือกว่าโซลูชันของ @Jacob Relkin:

นี่คือ ES2015:

const randomChoice = arr => {
    const randIndex = Math.floor(Math.random() * arr.length);
    return arr[randIndex];
};

รหัสทำงานโดยการเลือกตัวเลขสุ่มระหว่าง 0 ถึงความยาวของอาร์เรย์จากนั้นส่งคืนรายการที่ดัชนีนั้น


1

var item = myArray[Math.floor(Math.random()*myArray.length)];

หรือรุ่นที่สั้นกว่าเทียบเท่า:

var item = myArray[(Math.random()*myArray.length)|0];

รหัสตัวอย่าง:

var myArray = ['January', 'February', 'March'];    
var item = myArray[(Math.random()*myArray.length)|0];
console.log('item:', item);


1

ฟังก์ชั่นที่เรียบง่าย:

var myArray = ['January', 'February', 'March'];
function random(array) {
     return array[Math.floor(Math.random() * array.length)]
}
random(myArray);

หรือ

var myArray = ['January', 'February', 'March'];
function random() {
     return myArray[Math.floor(Math.random() * myArray.length)]
}
random();

หรือ

var myArray = ['January', 'February', 'March'];
function random() {
     return myArray[Math.floor(Math.random() * myArray.length)]
}
random();

มันจะเป็นการดีกว่าถ้าคุณตั้งค่าตัวแปร myArrayy ภายในฟังก์ชันของคุณเพื่อไม่สร้างมลภาวะเนมสเปซส่วนกลาง
Neil Meyer

0

ในความคิดของฉันดีกว่าไปยุ่งกับต้นแบบหรือประกาศทันเวลาฉันชอบเปิดเผยไปที่หน้าต่าง:

window.choice = function() {
  if (!this.length || this.length == 0) return;
  if (this.length == 1) return this[0];
  return this[Math.floor(Math.random()*this.length)];
}

ตอนนี้ทุกที่ในแอปของคุณที่คุณเรียกว่าชอบ:

var rand = window.choice.call(array)

วิธีนี้คุณยังสามารถใช้การfor(x in array)วนซ้ำได้อย่างถูกต้อง


1
ฉันไม่ได้อยู่ที่นี่เมื่อใครก็ตามที่ลงคะแนนและฉันไม่ได้ลงคะแนนเลย แต่การเดาของฉันคือการเปิดเผยให้หน้าต่างโดยทั่วไปแล้วจะประกาศตัวแปรระดับโลก ดู: stackoverflow.com/questions/2613310/…
Chris

1
คุณไม่ควรใช้for...inกับอาร์เรย์หรือโดยทั่วไป คุณเสี่ยงต่อการเดินโซ่ต้นแบบ มันมีความหมายสำหรับคุณสมบัติทั้งหมดของวัตถุไม่ใช่ดัชนีทั้งหมดในอาร์เรย์ หากคุณต้องการใช้ iterator for (var i = 0; i < foo.length; i++){}บนอาร์เรย์การใช้งาน ดียิ่งขึ้นใช้สิ่งที่ต้องการArray.prototype.forEachแทน
Robert

1
ฉันไม่ชอบสิ่งนี้เพราะมันสร้างความเสียหายต่อขอบเขตทั่วโลก คุณสามารถพูดได้ว่านี่อาจเป็นสิ่งเดียวที่จะอยู่ที่นั่น แต่มันจะให้นิสัยการละเมิดการฝึกฝนที่ดี
Jekk

0

ฉันได้พบวิธีแก้ไขภาวะแทรกซ้อนของคำตอบยอดนิยมเพียงแค่เชื่อมต่อตัวแปรแรนด์กับตัวแปรอื่นที่อนุญาตให้แสดงหมายเลขนั้นในการเรียก myArray []; ด้วยการลบอาเรย์ใหม่ที่สร้างและเล่นไปด้วยความยุ่งเหยิงฉันได้คิดวิธีแก้ปัญหาในการทำงาน:

<!DOCTYPE html>
<html>
<body>

<p id="demo"></p>

<script>

var myArray = ['January', 'February', 'March', 'April', 'May'];    

var rand = Math.floor(Math.random() * myArray.length);

var concat = myArray[rand];

function random() {
   document.getElementById("demo").innerHTML = (concat);
}
</script>

<button onClick="random();">
Working Random Array generator
</button>

</body>
</html>

ฉันสับสนว่าทำไมconcatการเปลี่ยนแปลงที่นี่ ... randomตัวเองไม่เปลี่ยนแปลงและไม่มีอะไรที่จะได้รับการเรียกมากกว่าหนึ่งครั้ง ....
BalinKingOfMoria Reinstate CMs

1
วิธีนี้ไม่สมเหตุสมผลเลย ทำไมคุณถึงสร้างตัวแปรชื่อ concat
แสงสว่าง

0

static generateMonth() { 
const theDate = ['January', 'February', 'March']; 
const randomNumber = Math.floor(Math.random()*3);
return theDate[randomNumber];
};

คุณตั้งค่าตัวแปรคงที่ให้กับอาร์เรย์จากนั้นคุณมีค่าคงที่อื่นที่เลือกแบบสุ่มระหว่างวัตถุทั้งสามในอาร์เรย์จากนั้นฟังก์ชันจะส่งคืนผลลัพธ์เพียงอย่างเดียว


-1

วิธีทั่วไปในการรับองค์ประกอบแบบสุ่ม:

let some_array = ['Jan', 'Feb', 'Mar', 'Apr', 'May'];
let months = random_elems(some_array, 3);

console.log(months);

function random_elems(arr, count) {
  let len = arr.length;
  let lookup = {};
  let tmp = [];

  if (count > len)
    count = len;

  for (let i = 0; i < count; i++) {
    let index;
    do {
      index = ~~(Math.random() * len);
    } while (index in lookup);
    lookup[index] = null;
    tmp.push(arr[index]);
  }

  return tmp;
}


-1

randojsทำให้ง่ายและอ่านได้ง่ายขึ้นเล็กน้อย:

console.log( rando(['January', 'February', 'March']).value );
<script src="https://randojs.com/1.0.0.js"></script>


1
แค่อยากรู้: ทำไมต้องลงคะแนน?
Leponzo

1
บางคนไม่ใช่แฟนของการจัดหาในไลบรารีสำหรับรหัสที่พวกเขาสามารถเขียนเองแม้ว่ามันจะทำให้สิ่งต่าง ๆ เร็วขึ้นและอ่านง่ายขึ้น หากห้องสมุดหยุดทำงานด้วยเหตุผลบางอย่างตอนนี้เว็บไซต์ของคุณมีข้อผิดพลาด randojs ไม่ได้ลงไป แต่พวกเขาไม่รู้ว่าเพราะมันไม่เป็นที่รู้จักกันดีในชื่อห้องสมุดเช่น jQuery
Aaron Plocharczyk

-2

นี่คือตัวอย่างของวิธีการ:

$scope.ctx.skills = data.result.skills;
    $scope.praiseTextArray = [
    "Hooray",
    "You\'re ready to move to a new skill", 
    "Yahoo! You completed a problem", 
    "You\'re doing great",  
    "You succeeded", 
    "That was a brave effort trying new problems", 
    "Your brain was working hard",
    "All your hard work is paying off",
    "Very nice job!, Let\'s see what you can do next",
    "Well done",
    "That was excellent work",
    "Awesome job",
    "You must feel good about doing such a great job",
    "Right on",
    "Great thinking",
    "Wonderful work",
    "You were right on top of that one",
    "Beautiful job",
    "Way to go",
    "Sensational effort"
  ];

  $scope.praiseTextWord = $scope.praiseTextArray[Math.floor(Math.random()*$scope.praiseTextArray.length)];


-3

สร้างหนึ่งค่าสุ่มและส่งผ่านไปยังอาร์เรย์

โปรดลองรหัสต่อไปนี้ ..

//For Search textbox random value
var myPlaceHolderArray = ['Hotels in New York...', 'Hotels in San Francisco...', 'Hotels Near Disney World...', 'Hotels in Atlanta...'];
var rand = Math.floor(Math.random() * myPlaceHolderArray.length);
var Placeholdervalue = myPlaceHolderArray[rand];

alert(Placeholdervalue);

5
คำตอบนี้ใช้โซลูชันเดียวกับคำตอบที่ยอมรับแล้ว คุณควรละเว้นจากการเพิ่มโซลูชันเดียวกันสองครั้งและนำเสนอทางเลือกอื่น ๆ ที่อาจมีส่วนร่วมในการสนทนามากขึ้น
Pixxl
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.