จะสร้างตัวเลขสุ่มได้อย่างไร?


23

ฉันต้องการสร้างตัวเลขสุ่มหนึ่งหรือสองสามตัวคั่นด้วยบรรทัดใหม่

วิธีนี้สามารถทำได้?


1
เป็นกลุ่มบริสุทธิ์? หรือว่าพูดโดยใช้:python?
muru

เป็นกลุ่มที่ต้องการความบริสุทธิ์ แต่ถ้าไม่ใช่ในตัววิธีการจดจำที่ง่าย ๆ ก็ใช้ได้
kenorb

คำตอบ:


20

ไม่มีสิ่งอำนวยความสะดวกในตัวสำหรับสิ่งนี้ดังนั้นคุณจะต้องใช้สิ่งภายนอก

UNIX Shell ( /bin/sh)

โทรศัพท์:

strings -n 1 < /dev/urandom | tr -d '[:space:]' | head -c15

ด้วยsystem()เป็นวิธีที่ดี คุณสามารถได้รับตัวเลขเท่านั้นโดยแทนที่trด้วยgrep:

strings -n 1 < /dev/urandom | grep -o '[[:digit:]]' | head -c15

คุณสามารถใช้สิ่งนี้เป็นกลุ่มอย่างเช่น:

:echo system("strings -n 1 < /dev/urandom | grep -o '[[:digit:]]'  | head -c15")

หมายเลข 15 คือจำนวนตัวเลขที่คุณต้องการ (ปรับตาม) สิ่งนี้ควรใช้กับ Linux, BSD, OSX และระบบ UNIX อื่น ๆ มันจะไม่ทำงานบน MS Windows

ดูเว็บบล็อกของฉันโพสต์ " สร้างรหัสผ่านจาก commandline " (มีวิธีแก้ปัญหาที่ไม่ดีมากมายสำหรับสิ่งนี้)

ทับทิม

Ruby อาจเป็นตัวเลือกที่ดีที่สุดต่อไปเนื่องจาก Ruby scripting ดูเหมือนจะเป็นเรื่องธรรมดามากกว่าการเขียนสคริปต์ Python การรับหมายเลขสุ่มนั้นง่ายมาก:

:ruby puts Random.rand(10)

หรือเพื่อรับ 15 หมายเลข:

:ruby 15.times { puts Random.rand(10) }

หลาม

คุณสามารถใช้โมดูลสุ่ม เพื่อรับหมายเลขเดียว:

:py import random; print(random.randint(0, 9))

หรือตัวเลข 15:

:py import random
:py for i in range(0, 15): print(random.randint(0, 9))

สิ่งนี้น่าจะใช้ได้กับทั้ง Python 2 และ 3

Windows PowerShell

คุณสามารถใช้Get-Random เพื่อรับหมายเลขสุ่ม:

:echo system('Get-Random')

ของ windows cmd.exe

Windows 7 และหลังจากนั้นควรมาพร้อมกับ PowerShell cmd.exeแต่ถ้าคุณต้องการความเข้ากันได้สูงสุดที่คุณสามารถใช้ มันมีตัวแปรพิเศษ%RANDOM%:

:echo system('@echo %RANDOM%')

หมายเหตุ: นี่ไม่สุ่มมาก! มันใช้เวลา (!)


โปรดทราบว่าคุณไม่จำเป็นต้องใช้การเชื่อม Ruby หรือ Python เพื่อใช้การแก้ปัญหา Ruby หรือ Python คุณสามารถสร้างสคริปต์แยกต่างหากและเรียกใช้ด้วย system("python -c '...'")(ต้องติดตั้ง ruby ​​/ python อย่างชัดเจน


แทนที่จะเป็นเช่นtr -d '[:space:]'นั้นtr -cd '[:digit:]'สำหรับตัวกรอง grep?
muru

@muru ผมไม่แน่ใจว่าจะทำงานใน OSX ซึ่งเป็นเหตุผลที่ผมไม่ได้ใช้มัน ... คุณยังได้รับตัวเลขที่คั่นด้วยการขึ้นบรรทัดใหม่ด้วยวิธีนี้เช่น OP ถาม ....
มาร์ติน Tournoij

ถ้าเป็นเช่นนั้น ... GNU ชนะ BSD : P
muru

หนึ่งสามารถใช้เชลล์ (ระบบ) สำหรับการป้อนตัวเลขแบบสุ่มเช่น:r! hexdump -n $((3*4)) -e '"%d"' /dev/urandomจะสร้างจำนวนเต็ม 3 เซ็นสัญญาแบบสุ่ม
HAL 9001

1
@kenorb สิ่งนี้จะใช้เชลล์อย่างถูกต้องสำหรับการป้อนจำนวนเต็มแบบสุ่ม 3 ลายเซ็น::r! hexdump -n $((3*4)) -e '"\%d\n"' /dev/urandom
HAL 9001

12

นี่คือวิธีแก้ปัญหาvimscript ที่แท้จริง ฉันไม่ได้สร้างมันมันถูกพัฒนาโดย Charles E. Campbell คุณสามารถค้นหา repo Github ด้วยรหัสของเขาที่นี่


อัลกอริทึมใช้ 3 เมล็ดที่สร้างขึ้นเมื่อเริ่มต้นกลุ่มและสร้างหมายเลขสุ่มหลอกขึ้นอยู่กับการคำนวณและการเรียงสับเปลี่ยนที่ใช้กับเมล็ด:

" Randomization Variables
" with a little extra randomized start from localtime()
let g:rndm_m1 = 32007779 + (localtime()%100 - 50)
let g:rndm_m2 = 23717810 + (localtime()/86400)%100
let g:rndm_m3 = 52636370 + (localtime()/3600)%100

ขอบเขตตัวแปรถูกประกาศเป็นโกลบอลเนื่องจากฟังก์ชันตัวสร้างจะถูกใช้ แต่อาจ จำกัด เฉพาะสคริปต์ ( s:)

และนี่คือฟังก์ชั่นเครื่องกำเนิดไฟฟ้า:

function! Rndm()
    let m4= g:rndm_m1 + g:rndm_m2 + g:rndm_m3
    if( g:rndm_m2 < 50000000 )
        let m4= m4 + 1357
    endif
    if( m4 >= 100000000 )
        let m4= m4 - 100000000
        if( m4 >= 100000000 )
            let m4= m4 - 100000000
        endif
    endif
    let g:rndm_m1 = g:rndm_m2
    let g:rndm_m2 = g:rndm_m3
    let g:rndm_m3 = m4
    return g:rndm_m3
endfun

repo มีฟังก์ชั่นต่อไปนี้:

  • การเริ่มต้น "สุ่ม" ของเมล็ด;
  • วิธีอ่าน seed ที่ผู้ใช้กำหนดเองจากไฟล์ข้อความ
  • เครื่องกำเนิดไฟฟ้าแบบหลอกหลอก
  • ฟังก์ชั่นสุ่มหลาย:
    • ฟังก์ชั่นที่สร้างตัวเลขสุ่มภายในช่วง
    • ฟังก์ชั่นการหมุนลูกเต๋า
    • ฟังก์ชั่นที่จะสลับรายการของจำนวนเต็มตามลำดับแบบสุ่ม

นี่คือการทดสอบอย่างรวดเร็วที่ฉันเขียนเพื่อทดสอบเครื่องกำเนิด: ฉันสร้าง 1000000 หมายเลขระหว่าง 0 และ 9 และนับจำนวนการเกิดขึ้นของแต่ละหมายเลขที่นี่คือผลลัพธ์:

0 : 100409
1 : 99435
2 : 100433
3 : 99578
4 : 100484
5 : 99948
6 : 100394
7 : 99649
8 : 99803
9 : 99867

อย่างที่คุณเห็นคนรุ่นนี้มีการกระจายตัวที่ดี ฉันรู้ว่านี่ไม่เพียงพอที่จะทดสอบเครื่องกำเนิดไฟฟ้าแบบสุ่มดังนั้นฉันจะพยายามวิเคราะห์เพิ่มเติมหากฉันมีเวลาว่าง


7

นี่คือวิธีการที่พบในกลุ่ม-randomtagปลั๊กอินซึ่งจะขึ้นอยู่กับการอ่าน ... microseconds เวลาปัจจุบันสามารถใช้งานได้เมื่อคุณต้องการเพียงแค่บางส่วนจำนวนที่คุณไม่สนใจมากเกี่ยวกับคุณภาพการสุ่มหรือมีปัญหาด้านความปลอดภัย ฯลฯ .:

function! s:randnum(max) abort
  return str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:]) % a:max
endfunction

4

เสียงเรียกเข้าไม่ได้มีตัวสร้างแบบสุ่มเนทิฟ แต่ถ้าคุณเป็นกลุ่มที่คอมไพล์ด้วย Python วิธีการต่อไปนี้จะต่อท้ายตัวเลขแบบสุ่มที่ท้ายบรรทัดของคุณ:

:py import vim, random; vim.current.line += str(random.randint(0, 9))

หมายเหตุ: ในการตรวจสอบว่ากลุ่มของคุณรองรับ Python หรือไม่ให้ลอง: :echo has('python')(1 สำหรับใช่)

คุณยังสามารถใช้เชลล์ที่เสนอ$RANDOMตัวแปร (ทำงานกับ bash / ksh / zsh) ซึ่งส่งคืน pseudorandom (0-32767) ในตัวอย่าง:

:r! echo $RANDOM

หรือ:

:put =system('echo $RANDOM')

หรือ:

:r! od -An -td -N1 /dev/urandom

บน Windows คุณต้องติดตั้ง Cygwin / MSYS / SUA หรือใช้%RANDOM%ตัวแปรตามที่Carpetsmokerแนะนำ

หากคุณไม่มีสิทธิ์เข้าถึงเชลล์และ Python สำหรับวิธีแก้ปัญหาคุณสามารถใช้ตัวเลขสองสามหลักสุดท้ายจากเวลาประทับปัจจุบันตัวอย่างเช่น

:put =reltimestr(reltime())[-2:]

หมายเหตุ: หากคุณใช้งานบ่อยให้เขียนฟังก์ชั่นง่ายๆที่จะreturn reltimestr(reltime())[-4:]ใช้

หมายเหตุ: เมธอดด้านบนจะส่งคืนเฉพาะจำนวนเต็มเทียมซึ่งไม่ควรใช้เพื่อสร้างคีย์การเข้ารหัส


หากต้องการเพิ่มหมายเลขสุ่มเพิ่มเติมให้กด@:เพื่อทำซ้ำคำสั่งอีกครั้ง หรือคำนำหน้าด้วยหมายเลข (เช่น10@:) เพื่อเพิ่มจำนวนสุ่มจำนวนมากคั่นด้วยบรรทัดใหม่


ที่เกี่ยวข้อง:


นอกจากนี้ยังทำงานร่วมกับzshแต่ไม่ได้มีsh, dash, fish, cshหรือtcsh... คุณสามารถใช้:r! bash -c 'echo $RANDOM'...
มาร์ติน Tournoij

"ส่งคืนตัวเลขสองสามหลักสุดท้ายจากเวลาปัจจุบัน" -> นี่ไม่ใช่การสุ่ม การใช้เวลาในการรับหมายเลขหลอกแบบสุ่มนั้นเป็นความคิดที่ไม่ดีเสมอไปแม้แต่ในจุดประสงค์ที่ไม่ใช่การเข้ารหัส ถ้าความละเอียดของการประทับเวลาเป็นวินาทีและคุณสร้าง "ไฟล์ $ random" สองครั้งในหนึ่งวินาที? อ๊ะ! ... นอกจากนี้คุณไม่มีทางรู้ว่าใครบางคนจะใช้GetRandom()ฟังก์ชั่นที่ PRNG ที่ดีไม่ว่าดังนั้นจึงเป็นเรื่องที่ดีกว่าที่จะเพียงแค่ได้รับมันขวาจากจุดเริ่มต้นถ้าเป็นไปได้ (และก็เกือบจะเป็นไปได้เสมอที่นี่!)
มาร์ติน Tournoij

ฉันไม่รู้ว่าคุณภาพของ$RANDOMมันคืออะไร แต่ถ้านี่เป็น PRNG ที่แย่นั่นก็ไม่ใช่เหตุผลที่จะใช้ PRNG ที่แย่กว่านี้ :-) แทนที่จะอัพเกรดเป็น PRNG ที่ดีกว่า! เท่าที่ฉันรู้/dev/urandomมีอยู่ในทุกแพลตฟอร์มที่bashมีอยู่ทั่วไปดังนั้นฉันจึงไม่เห็นเหตุผลที่จะไม่ใช้มัน
Martin Tournoij

1
$RANDOMผมไม่ทราบเกี่ยวกับ ดูเหมือนจะเป็นเครื่องมือเล็ก ๆ ที่ดีมากและถึงแม้ว่ามันอาจจะเป็น "คนจน RNG" (@Carpetsmoker ชี้ให้เห็น) แต่มันเหมาะกับข้อกำหนดของ @ kenorb (ผู้ถามคำถาม) อย่างแน่นอนว่า "จดจำได้ง่าย"
Dalker

4

คุณสามารถใช้rand()และsrand()ฟังก์ชั่นให้ไบนารีที่เป็นกลุ่มของคุณมีแพทช์2342/01/08


ตัวอย่างการสร้างตัวเลขสุ่ม 10 ตัวคั่นด้วยการขึ้นบรรทัดใหม่:

let seed = srand()
echo range(10)->map({-> rand(g:seed)})->join("\n")

ในการสร้างตัวเลขสุ่ม 10 หมายเลขทั้งหมดจะต่ำกว่า 100

let seed = srand()
echo range(10)->map({-> rand(g:seed) % 100})->join("\n")

ในการสร้างสตริงตัวอักษรแบบสุ่มจำนวน 10 ตัวจาก 5 ตัวอักษร:

let seed = srand()
echo range(10)
   \ ->map({-> range(5)
   \           ->map({-> (97+rand(g:seed) % 26)->nr2char()})->join('')})
   \ ->join("\n")

วิธีสร้างคำสุ่ม 10 คำ (นำมาจากไฟล์พจนานุกรม/usr/share/dict/words):

let seed = srand()
let words = readfile('/usr/share/dict/words')
let len = len(words)
echo range(10)->map({-> g:words[rand(g:seed) % g:len]})->join("\n")

หากต้องการสร้าง 10 ลำดับจาก 5 คำสุ่ม:

let seed = srand()
let words = readfile('/usr/share/dict/words')
let len = len(words)
echo range(10)
   \ ->map({-> range(5)
   \           ->map({-> g:words[rand(g:seed) % g:len]})->join()})
   \ ->join("\n")

ในการสร้าง UUID แบบสุ่มรุ่น 4:

" Based on this answer: /programming//a/38191078/9780968
let seed = srand()
let random_numbers = range(30)->map({-> rand(g:seed) % 16})
echo call('printf', ['%x%x%x%x%x%x%x%x-%x%x%x%x-4%x%x%x'] + random_numbers[:14])
 \ ..call('printf', ['-X%x%x%x-%x%x%x%x%x%x%x%x%x%x%x%x'] + random_numbers[15:])
 \   ->substitute('X', '89ab'[rand(seed) % 4], '')

ในการใช้ชุดรูปแบบสีแบบสุ่ม:

let seed = srand()
let colorschemes = getcompletion('', 'color')
let len = colorschemes->len()
exe 'colo '..colorschemes[rand(seed) % len]

3

ฉันไม่คิดว่าจะมีฟังก์ชันเนทีฟสำหรับการสุ่มตัวเลขใน Vimscript

วิธีใช้:python(ใช้ในฟังก์ชั่นบางทีด้วย 10,000 และ 60 แทนที่ด้วยพารามิเตอร์):

:python <<EOF
import vim
import random

line = vim.current.window.cursor[0]
r = getattr(__builtins__, 'xrange', range) # To make it work for both Python 2 & 3
vim.current.buffer[line:line] = list(map(str, random.sample(r(10000), 60)))
EOF

ดูคำตอบของฉันในการสร้างกล่องเป็นกลุ่มผ่าน pythonสำหรับคำแนะนำสั้น ๆ เกี่ยวกับสคริปต์ Python ใน Vim

เนื่องจากvim.current.bufferเป็นรายการของสตริงเราสามารถกำหนดรายการของสตริงให้เหมือนกับที่เราทำใน Python random.sampleเป็นวิธีที่ง่ายที่สุดที่ฉันสามารถคิดได้ว่าจะรับรายการจำนวนเต็มแบบสุ่มใน Python


@Carpetsmoker random.samplerepuires เพียงสองข้อโต้แย้งใน Python 2 strเป็นฟังก์ชั่น builtin เพื่อแปลงสิ่งต่าง ๆ เป็นสตริง ให้ฉันดู Py3 เทียบเท่า ( strจะเหมือนกันจะต้องตรวจสอบxrangeและrandom.sample)
muru

@Carpetsmoker aargh, พิมพ์ผิด วงเล็บหลัง 60 ควรเป็นหลัง 10,000 และxrangeไม่ได้อยู่ใน Python3 เพราะrangeเทียบเท่า (ไม่ได้สร้างรายการเหมือนrangeใน Py2 จริง ๆ )
muru

@Carpetsmoker และความแตกต่างสุดท้ายก็คือว่าmapใน Py3 กลับ iterable และไม่ใช่รายการดังนั้นบรรทัดสุดท้ายจะใช้list(map(str, random.sample(range(10000), 60)))
Muru

โอเคฉันมีอิสระที่จะแก้ไขโพสต์ของคุณด้วยการเปลี่ยนแปลง (เล็กน้อย) เพื่อให้เข้ากันได้กับทั้ง Python 2 และ 3 ...
Martin Tournoij
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.