วิธีรับหมายเลขสุ่มใน Ruby


786

ฉันจะสร้างตัวเลขสุ่มระหว่าง0และได้nอย่างไร


การใช้โค้ดsrand <some_number>ก่อนการเขียนrandจะทำให้คุณมีลำดับการสุ่มหลอก (เช่นทำซ้ำได้) หากคุณต้องการ ruby-doc.org/core-2.5.6/Random.html#method-c-srand
Purplejacket

คำตอบ:


952

ใช้ rand(range)

จากหมายเลขสุ่มทับทิม :

1 + rand(6)หากคุณจำเป็นต้องเป็นจำนวนเต็มสุ่มเพื่อจำลองม้วนตายหกด้านที่คุณต้องการใช้: 2 + rand(6) + rand(6)ม้วนในลูกเต๋าชนิดหนึ่งอาจจะมีการจำลองด้วย

ท้ายที่สุดถ้าคุณต้องการทุ่นแบบสุ่มเพียงแค่โทรrandโดยไม่มีข้อโต้แย้ง


ในฐานะที่เป็นMarc-André Lafortuneกล่าวถึงในคำตอบของเขาด้านล่าง (ขึ้นไปโหวต) , Ruby 1.9.2 มีRandomคลาสของตัวเอง (Marc-Andréนั้นเองช่วยให้ debug , ดังนั้น1.9.2 เป้าหมายสำหรับคุณสมบัตินั้น)

ตัวอย่างเช่นในเกมนี้ที่คุณต้องเดาตัวเลข 10 ตัวคุณสามารถเริ่มต้นด้วย:

10.times.map{ 20 + Random.rand(11) } 
#=> [26, 26, 22, 20, 30, 26, 23, 23, 25, 22]

บันทึก:

นี่คือเหตุผลที่Random.new.rand(20..30)จะเท่ากับ20 + Random.rand(11)เนื่องจากRandom.rand(int)ส่งกลับ "จำนวนเต็มแบบสุ่มมากกว่าหรือเท่ากับศูนย์และน้อยกว่าการโต้แย้ง " 20..30รวม 30 ฉันต้องหาตัวเลขสุ่มระหว่าง 0 ถึง 11 ไม่รวม 11


2
นี่ไม่ใช่สิ่งที่ไม่เหมือนทับทิมมากใช่ไหม ผมคิดว่าทุกอย่างเป็นวัตถุอย่างน้อยความประหลาดใจและว่า ...
แดน Rosenstark

1
@yar: มันเป็นบิต "perlish" ตอนนี้ Ruby มีคลาสแบบสุ่ม (ดูคำตอบของฉัน)
Marc-André Lafortune

3
@VonC: มันดีมากที่คุณแก้ไขคำตอบของคุณเพื่อพูดถึงRandomคลาสใหม่แต่มันเป็นความคิดที่แย่มากที่จะโทรหาคุณRandom.newหลาย ๆ ครั้งเหมือนในตัวอย่างของคุณ ฉันได้แก้ไขคำตอบของฉันเพื่อระบุว่า
Marc-André Lafortune

2
@VonC ah :) ขออภัยถ้าฉันเป็นคนที่ค่อนข้างรุนแรงมันก็ทำให้ฉันประหลาดใจ
horseyguy

1
Random.rand ไม่ยอมรับช่วงจริง (ตั้งแต่ 1.9.3 ฉันเชื่อ)
Ajedi32

591

ในขณะที่คุณสามารถใช้rand(42-10) + 10เพื่อรับหมายเลขสุ่มระหว่าง10และ42(โดยที่ 10 รวมและ 42 พิเศษ) มีวิธีที่ดีกว่าตั้งแต่ Ruby 1.9.3 ซึ่งคุณสามารถโทรได้:

rand(10...42) # => 13

มีให้สำหรับทับทิมทุกรุ่นโดยต้องการbackportsอัญมณีของฉัน

Ruby 1.9.2 ยังแนะนำRandomคลาสเพื่อให้คุณสามารถสร้างออบเจ็กต์ตัวสร้างตัวเลขสุ่มของคุณเองและมี API ที่ดี:

r = Random.new
r.rand(10...42) # => 22
r.bytes(3) # => "rnd"

Randomระดับตัวเองทำหน้าที่เป็นเครื่องกำเนิดไฟฟ้าแบบสุ่มเพื่อให้คุณโดยตรงโทร:

Random.rand(10...42) # => same as rand(10...42)

หมายเหตุเกี่ยวกับ Random.new

ในกรณีส่วนใหญ่ที่ง่ายที่สุดคือการใช้หรือrand Random.randการสร้างเครื่องกำเนิดไฟฟ้าแบบสุ่มใหม่ทุกครั้งที่คุณต้องการจำนวนสุ่มเป็นความคิดที่ดีจริงๆ ถ้าคุณทำเช่นนี้คุณจะได้รับคุณสมบัติที่สุ่มของขั้นตอนวิธีการเพาะเริ่มต้นที่เลวร้ายเมื่อเทียบกับคุณสมบัติของเครื่องกำเนิดไฟฟ้าแบบสุ่มตัวเอง

หากคุณใช้Random.newคุณควรเรียกมันน้อยที่สุดเท่าที่จะเป็นไปได้ตัวอย่างเช่นใช้ครั้งเดียวMyApp::Random = Random.newและใช้ทุกที่อื่น

กรณีที่Random.newมีประโยชน์มีดังต่อไปนี้:

  • คุณกำลังเขียนอัญมณีและไม่ต้องการยุ่งเกี่ยวกับลำดับrand/ Random.randว่าโปรแกรมหลักอาจต้องพึ่งพา
  • คุณต้องการลำดับการทำซ้ำของตัวเลขสุ่ม (พูดหนึ่งรายการต่อเธรด)
  • คุณต้องการที่จะสามารถบันทึกและดำเนินการต่อลำดับตัวเลขที่สุ่มทำซ้ำ (ง่าย ๆ เป็นRandomวัตถุสามารถ marshalled)

1
ยอดเยี่ยม +1 ฉันได้ตอบคำถามของฉันเองแล้วเพื่อสะท้อนให้เห็นถึงคุณลักษณะใหม่ (และกล่าวถึงการบริจาคของคุณใน Bug # 3104;)
VonC

1
@yar: backportsอัญมณีของฉันเป็นเพียงชุดของวิธีการใหม่สำหรับ RUby 1.8.7, 1.9.1, 1.9.2 แต่มีการใช้งานใน Ruby ฉันใช้ RubySpec เพื่อรับรองว่าผลลัพธ์เข้ากันได้กับ Ruby
Marc-André Lafortune

@ Marc-André Lafortune ขอบคุณสำหรับสิ่งนั้น มันแปลกสำหรับฉันเสมอว่าทับทิมมีการนำไปใช้ในแบบใดที่ไม่ใช่ Ruby (C หรืออะไรก็ตาม) เนื่องจากความต้องการด้านความเร็ว แต่พวกเขาก็หยุดพัก
Dan Rosenstark

5
Random.rand(10..42)ไม่ทำงาน, ไม่เป็นผล. Random.randวิธีการเรียนไม่ยอมรับช่วง (ทับทิม 1.9.2p180)
horseyguy

1
@banister: ว้าวฉันมั่นใจว่า api ใหม่ (แรนด์ที่มีช่วงไบต์ ฯลฯ ... ) มีให้ใช้โดยตรงผ่านวัตถุสุ่ม แรนด์ที่มีช่วงจะอยู่ใน 1.9.3 และฉันจะทำการร้องขอคุณสมบัติสำหรับไบต์ ฉันแก้ไขคำตอบของฉันแล้ว
Marc-André Lafortune

46

หากคุณไม่เพียง แต่กำลังมองหาตัวเลข แต่ยังเป็นเลขฐานสิบหกหรือ uuid ก็คุ้มค่าที่จะกล่าวถึงว่าSecureRandomโมดูลนั้นหามาได้จากActiveSupportไปยังแกนทับทิมใน 1.9.2+ ดังนั้นโดยไม่จำเป็นต้องมีกรอบการทำงานแบบเต็มเป่า:

require 'securerandom'

p SecureRandom.random_number(100) #=> 15
p SecureRandom.random_number(100) #=> 88

p SecureRandom.random_number #=> 0.596506046187744
p SecureRandom.random_number #=> 0.350621695741409

p SecureRandom.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"

มีการบันทึกไว้ที่นี่: Ruby 1.9.3 - โมดูล: SecureRandom (lib / securerandom.rb)


ถ้าคุณต้องการตัวเลขสุ่ม 4 หลักล่ะ
onurozgurozkan

1
onurozgurozkan ฉันเข้าใจSecureRandom.random_number(1000..9999)
JayTarka

1
SecureRandom.random_number()ไม่ใช้ช่วงดังนั้นไม่ คุณอาจต้องการบางสิ่งเช่นSecureRandom.random_number(10_000)(สำหรับ 0-9999) หรือSecureRandom.random_number(9_000)+1_000(สำหรับ 1,000-9999)
mwp

1
Random.rand (1,000..9999)
Jesse Farmer

37

คุณสามารถสร้างตัวเลขสุ่มด้วยrandวิธีการ อาร์กิวเมนต์ที่ส่งไปยังrandเมธอดควรเป็นintegera หรือ a rangeและส่งคืนตัวเลขสุ่มที่สอดคล้องกันภายในช่วง:

rand(9)       # this generates a number between 0 to 8
rand(0 .. 9)  # this generates a number between 0 to 9
rand(1 .. 50) # this generates a number between 1 to 50
#rand(m .. n) # m is the start of the number range, n is the end of number range

ผมคิดว่าการใช้ของคุณอ่านชัดเจนกว่าคำตอบที่ด้านบนของrand(1..6) rand(6)+1
isomorphismes

21

ฉันก็คิดออก เห็นได้ชัดว่ามีฟังก์ชั่น builtin (?) ที่เรียกว่า rand:

rand(n + 1)

หากมีคนตอบด้วยคำตอบที่ละเอียดกว่านี้ฉันจะทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้อง


2
ใช่มันสร้างขึ้นในโมดูลเคอร์เนล
Christoph Schiessl

17

แล้วเรื่องนี้ล่ะ

n = 3
(0..n).to_a.sample

3
ควรสังเกตว่าการสร้างอาร์เรย์ของจำนวนเช่นวิธีนี้ให้มีประสิทธิภาพที่ดีในช่วงใหญ่เนื่องจากเป็น O (n) ในขณะที่randO (1)
เทรวิส


9

คุณสามารถใช้ random_numberคุณก็สามารถใช้

หากได้รับจำนวนเต็มบวกเป็น n random_numberจะส่งคืนจำนวนเต็ม: 0 <= random_number<n

ใช้แบบนี้:

any_number = SecureRandom.random_number(100) 

เอาต์พุตจะเป็นตัวเลขใด ๆ ระหว่าง 0 ถึง 100


6
rand(6)    #=> gives a random number between 0 and 6 inclusively 
rand(1..6) #=> gives a random number between 1 and 6 inclusively

โปรดทราบว่าตัวเลือกช่วงนั้นมีเฉพาะในทับทิมเวอร์ชันใหม่กว่า (1.9+ ฉันเชื่อ)


ruby 1.9.3+ผมเชื่อว่าตัวเลือกช่วงนี้จะใช้ได้เฉพาะใน มันไม่ทำงาน1.9.2เมื่อฉันพยายามอย่างน้อย
Batkins

6

ช่วง = 10..50

แรนด์ (ช่วง)

หรือ

range.to_a.sample

หรือ

range.to_a.shuffle (การทำเช่นนี้จะเป็นการสลับทั้งอาร์เรย์และคุณสามารถเลือกหมายเลขสุ่มโดยเลือกหนึ่งหรือสุดท้ายหรือใดก็ได้จากอาร์เรย์นี้เพื่อเลือกสุ่ม)


range.to_a.sampleเป็นความคิดที่น่ากลัวเมื่อตัวอย่างมีขนาดใหญ่
Grzegorz


4

ลิงค์นี้จะมีประโยชน์เกี่ยวกับเรื่องนี้;

http://ruby-doc.org/core-1.9.3/Random.html

และความชัดเจนยิ่งขึ้นด้านล่างของตัวเลขสุ่มในทับทิม

สร้างจำนวนเต็มตั้งแต่ 0 ถึง 10

puts (rand() * 10).to_i

สร้างตัวเลขตั้งแต่ 0 ถึง 10 ด้วยวิธีที่อ่านได้ง่ายขึ้น

puts rand(10)

สร้างตัวเลขตั้งแต่ 10 ถึง 15 รวมถึง 15

puts rand(10..15)

ตัวเลขสุ่มแบบไม่สุ่ม

สร้างลำดับหมายเลขที่เหมือนกันทุกครั้งที่มีการเรียกใช้โปรแกรม

srand(5)

สร้างตัวเลขสุ่ม 10 หมายเลข

puts (0..10).map{rand(0..10)}

นอกจากนี้คุณสามารถติดตามบล็อกนี้ทีละขั้นตอนภาพที่ชัดเจนมากผ่าน nos สุ่มในทับทิม; sitepoint.com/tour-random-ruby
Sam

4

วิธีง่ายๆในการรับจำนวนสุ่มในทับทิมคือ

def random    
  (1..10).to_a.sample.to_s
end

2

บางทีมันอาจช่วยคุณได้ ฉันใช้สิ่งนี้ในแอพของฉัน

https://github.com/rubyworks/facets
class String

  # Create a random String of given length, using given character set
  #
  # Character set is an Array which can contain Ranges, Arrays, Characters
  #
  # Examples
  #
  #     String.random
  #     => "D9DxFIaqR3dr8Ct1AfmFxHxqGsmA4Oz3"
  #
  #     String.random(10)
  #     => "t8BIna341S"
  #
  #     String.random(10, ['a'..'z'])
  #     => "nstpvixfri"
  #
  #     String.random(10, ['0'..'9'] )
  #     => "0982541042"
  #
  #     String.random(10, ['0'..'9','A'..'F'] )
  #     => "3EBF48AD3D"
  #
  #     BASE64_CHAR_SET =  ["A".."Z", "a".."z", "0".."9", '_', '-']
  #     String.random(10, BASE64_CHAR_SET)
  #     => "xM_1t3qcNn"
  #
  #     SPECIAL_CHARS = ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "=", "+", "|", "/", "?", ".", ",", ";", ":", "~", "`", "[", "]", "{", "}", "<", ">"]
  #     BASE91_CHAR_SET =  ["A".."Z", "a".."z", "0".."9", SPECIAL_CHARS]
  #     String.random(10, BASE91_CHAR_SET)
  #      => "S(Z]z,J{v;"
  #
  # CREDIT: Tilo Sloboda
  #
  # SEE: https://gist.github.com/tilo/3ee8d94871d30416feba
  #
  # TODO: Move to random.rb in standard library?

  def self.random(len=32, character_set = ["A".."Z", "a".."z", "0".."9"])
    chars = character_set.map{|x| x.is_a?(Range) ? x.to_a : x }.flatten
    Array.new(len){ chars.sample }.join
  end

end

https://github.com/rubyworks/facets/blob/5569b03b4c6fd25897444a266ffe25872284be2b/lib/core/facets/string/random.rb

มันใช้งานได้ดีสำหรับฉัน



1

ลองarray#shuffleวิธีการสุ่ม

array = (1..10).to_a
array.shuffle.first

1
หากคุณต้องสร้างอาร์เรย์ทั้งหมดอย่างน้อยก็แทนที่.shuffle.firstด้วย.sample!
Camille Goudeseune

0

อย่าลืมหว่าน RNG ด้วยsrand ()ก่อน


2
จะเกิดอะไรขึ้นถ้าคุณไม่โทร srand ()
อเล็กซ์ B

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