Đọc n dòng ngẫu nhiên từ một tệp có khả năng rất lớn


16

Thử thách này là về việc đọc các dòng ngẫu nhiên từ một tệp có khả năng rất lớn mà không cần đọc toàn bộ tệp vào bộ nhớ.

Đầu vào

Một số nguyên nvà tên của một tệp văn bản.

Đầu ra

n các dòng của tệp văn bản được chọn thống nhất ngẫu nhiên mà không thay thế.

Bạn có thể giả sử rằng ntrong phạm vi 1 đến số dòng trong tệp.

Hãy cẩn thận khi lấy mẫu nsố ngẫu nhiên trong phạm vi mà câu trả lời bạn nhận được là thống nhất. rand()%ntrong C không đồng nhất chẳng hạn. Mọi kết quả đều phải có khả năng như nhau.

Các quy tắc và hạn chế

Mỗi dòng của tệp văn bản sẽ có cùng số lượng ký tự và sẽ không quá 80.

Mã của bạn không được đọc bất kỳ nội dung nào của tệp văn bản ngoại trừ:

  • Những dòng nó đầu ra.
  • Dòng đầu tiên để tìm ra có bao nhiêu ký tự trên mỗi dòng trong tệp văn bản.

Chúng ta có thể giả sử mỗi ký tự trong tệp văn bản mất chính xác một byte.

Dấu phân cách dòng được giả sử là dài 1 byte. Các giải pháp có thể sử dụng dấu phân cách dòng dài 2 byte chỉ khi chúng chỉ định nhu cầu này. Bạn cũng có thể giả sử dòng cuối cùng được kết thúc bằng dấu phân cách dòng.

Câu trả lời của bạn phải là một chương trình hoàn chỉnh nhưng bạn có thể chỉ định đầu vào theo bất kỳ cách nào thuận tiện.

Ngôn ngữ và thư viện

Bạn có thể sử dụng bất kỳ ngôn ngữ hoặc thư viện nào bạn thích.

Ghi chú

Có một mối quan tâm về việc tính toán số lượng dòng trong tệp. Như nimi chỉ ra trong các bình luận, bạn có thể suy ra điều này từ kích thước tệp và số ký tự trên mỗi dòng.

Động lực

Trong cuộc trò chuyện, một số người hỏi liệu đây có thực sự là câu hỏi "Làm X mà không có Y" không. Tôi giải thích điều này để hỏi nếu các hạn chế là nhân tạo bất thường.

Nhiệm vụ lấy mẫu ngẫu nhiên các dòng từ các tệp lớn không phải là hiếm và trên thực tế đôi khi tôi phải làm. Một cách để làm điều này là trong bash:

shuf -n <num-lines>

Tuy nhiên, điều này rất chậm đối với các tệp lớn vì nó đọc trong toàn bộ tệp.


Tại sao các downvote?

3
Điều này là tầm thường trong các ngôn ngữ như C có fseekvà không thể có trong các ngôn ngữ khác. Ngoài ra, nếu nlớn hơn số lượng dòng trong tệp thì sao?
Mego

4
@Mego: liên quan đến điểm của bạn b): bạn có thể tính số lượng dòng bằng cách chia kích thước tệp cho độ dài của một dòng.
nimi

8
Làm X mà không có Y là một cảnh báo bắt đầu bằng "Điều này không phải lúc nào cũng xấu". Vấn đề chính là các hạn chế nhân tạo như "không sử dụng +", điều này mang lại lợi thế cho các ngôn ngữ có a sum(). Không đọc một tập tin vào bộ nhớ là một hạn chế rõ ràng và nhất quán, không có cách nào tùy tiện. Nó có thể được kiểm tra với một tệp lớn hơn bộ nhớ, không thể xử lý được bằng các khác biệt ngôn ngữ. Nó cũng có các ứng dụng trong thế giới thực (mặc dù điều đó không cần thiết cho một môn đánh gôn ...).
trichoplax

1
Có vẻ như đây thực sự là một sân golf mã phức tạp bị hạn chế trong đó việc sử dụng bộ nhớ bị hạn chế mặc dù có khả năng rất lớn. Đó không phải là về việc không có những thứ nhất định trong mã của bạn mà là giới hạn về cách mã có thể hoạt động.
xnor

Câu trả lời:


5

APL Dyalog , 63 byte

⎕NREAD¨t 82l∘,¨lׯ1+⎕?(⎕NSIZE t)÷l←10⍳⍨⎕NREAD 83 80,⍨t←⍞⎕NTIE 0

Nhắc tên tệp, sau đó cho bao nhiêu dòng ngẫu nhiên mong muốn.

Giải trình

Nhắc nhở nhập văn bản (tên tệp)
⎕NTIE 0Buộc tệp bằng số liên kết có sẵn tiếp theo (-1 trên hệ thống sạch)
t←Lưu số cà vạt đã chọn là t
83 80,⍨Nối [83,80] mang lại [-1,83,80]
⎕NREADĐọc 80 byte đầu tiên của tệp -1 dưới dạng số nguyên 8 bit (mã chuyển đổi 83)
10⍳⍨Tìm chỉ mục của số 10 đầu tiên (LF)
l←Lưu trữ độ dài dòng dưới dạng l
(⎕NSIZE t)÷Chia kích thước của tệp -1 với độ dài dòng
Nhắc cho đầu vào số (số dòng mong muốn )
?X lựa chọn ngẫu nhiên (không thay thế) ngoài các số tự nhiên Y đầu tiên
¯1+Thêm -1 để lấy số dòng gốc 0 *
Nhân với độ dài dòng để lấy byte bắt đầu
t 82l∘,¨Chuẩn bị [-1,82, LineLạng] cho mỗi byte bắt đầu (tạo danh sách các đối số cho ⎕NREAD)
⎕NREAD¨ Đọc từng dòng dưới dạng ký tự 8 bit (mã chuyển đổi 82)

Ví dụ thực tế

Tệp /tmp/records.txt chứa:

Hello
Think
12345
Klaus
Nilad

Làm cho chương trình RandLines chứa mã nguyên văn ở trên bằng cách nhập đoạn mã sau vào phiên APL:

∇RandLines
⎕NREAD¨t 82l∘,¨lׯ1+⎕?(⎕NSIZE t)÷l←10⍳⍨⎕NREAD 83 80,⍨t←⍞⎕NTIE 0
∇

Trong loại phiên APL RandLinesvà nhấn Enter.

Hệ thống di chuyển con trỏ đến dòng tiếp theo, đó là lời nhắc 0 độ dài cho dữ liệu ký tự; nhập /tmp/records.txt.

Hệ thống hiện xuất ra ⎕:và chờ đầu vào số; nhập 4.

Hệ thống xuất ra bốn dòng ngẫu nhiên.

Đời thực

Trong thực tế, bạn có thể muốn cung cấp tên tệp và tính là đối số và nhận kết quả dưới dạng bảng. Điều này có thể được thực hiện bằng cách nhập:

RandLs←{↑⎕NREAD¨t 82l∘,¨lׯ1+⍺?(⎕NSIZE t)÷l←10⍳⍨⎕NREAD 83 80,⍨t←⍵⎕NTIE 0}

Bây giờ bạn tạo MyLines chứa ba dòng ngẫu nhiên với:

MyLines←3 RandLs'/tmp/records.txt'

Làm thế nào về việc chỉ trả về một dòng ngẫu nhiên duy nhất nếu số lượng không được chỉ định:

RandL←{⍺←1 ⋄ ↑⎕NREAD¨t 82l∘,¨lׯ1+⍺?(⎕NSIZE t)÷l←10⍳⍨⎕NREAD 83 80,⍨t←⍵⎕NTIE 0}

Bây giờ bạn có thể làm cả hai:

MyLines←2 RandL'/tmp/records.txt'

và (thông báo không có đối số bên trái):

MyLine←RandL'/tmp/records.txt'

Làm cho mã có thể đọc được

Golf một lớp lót APL là một ý tưởng tồi. Đây là cách tôi sẽ viết trong một hệ thống sản xuất:

RandL←{ ⍝ Read X random lines from file Y without reading entire file
    ⍺←1 ⍝ default count
    tie←⍵⎕NTIE 0 ⍝ tie file
    length←10⍳⍨⎕NREAD 83 80,⍨tie ⍝ find first NL
    size←⎕NSIZE tie ⍝ total file length
    starts←lengthׯ1+⍺?size÷length ⍝ beginning of each line
    ↑⎕NREAD¨tie 82length∘,¨starts ⍝ read each line as character and convert list to table
}

* Tôi có thể lưu một byte bằng cách chạy ở chế độ 0 gốc, là tiêu chuẩn trên một số hệ thống APL: xóa ¯1+và chèn 1+trước đó 10.


Ahh .. APL :) Có cách nào để kiểm tra mã này trong linux không?

@Lembik Chắc chắn, mã này là nền tảng chéo. Tải xuống từ dyalog.com
Adám

Khi tôi không đọc APL, bạn có thể giải thích mã không? Các phần khó khăn là lấy mẫu các dòng mà không thay thế và nhảy trực tiếp đến đúng nơi trong tệp để đọc các dòng.

@Lembik Phần đó dễ. Đối số của ⎕NREAD là TieNumber ConverterCode BytesToRead [StartByte]. Nó chỉ đọc các byte cần thiết. Phần còn lại chỉ là tìm ra những gì để đọc.
Adám

@Lembik Tôi tò mò tại sao câu trả lời của tôi không giành được tiền thưởng.
Adám

7

Ruby, 104 94 92 90 byte

Tên tệp và số dòng được truyền vào dòng lệnh. Ví dụ: nếu chương trình là shuffle.rbvà tên tệp là a.txt, hãy chạy ruby shuffle.rb a.txt 3ba dòng ngẫu nhiên.

-4 byte từ việc khám phá opencú pháp trong Ruby thay vìFile.new

f=open$*[0]
puts [*0..f.size/n=f.gets.size+1].sample($*[1].to_i).map{|e|f.seek n*e;f.gets}

Ngoài ra, đây là một giải pháp hàm ẩn danh 85 byte lấy một chuỗi và một số làm đối số của nó.

->f,l{f=open f;puts [*0..f.size/n=f.gets.size+1].sample(l).map{|e|f.seek n*e;f.gets}}

Dưới 100 byte! Có lẽ Ruby là ngôn ngữ chơi golf tốt nhất sau tất cả. Liệu 'mẫu' có tránh được sự lặp lại?

@Lembik ruby-doc.org/core-2.2.0/Array.html#method-i-sample Nó tránh sự lặp lại. Đừng nói với tôi ... tôi có nên lặp đi lặp lại không?
Mực giá trị

Không có bạn là hoàn hảo :)

Bạn có thể lưu bất kỳ byte bằng cách đọc từ stdin? ruby shuffle.rb 3 < a.txtcung cấp cho bạn một stdin tìm kiếm. IDK Ruby, mặc dù.
Peter Cordes

1
@PeterCordes Điều đó có ý nghĩa, nhưng như đã đề cập, điểm thất bại là Ruby không thể đọc kích thước tệp của stdin, vì vậy nó không hoạt động.
Mực giá trị

5

Haskell, 240 224 236 byte

import Test.QuickCheck
import System.IO
g=hGetLine
main=do;f<-getLine;n<-readLn;h<-openFile f ReadMode;l<-(\x->1+sum[1|_<-x])<$>g h;s<-hFileSize h;generate(shuffle[0..div s l-1])>>=mapM(\p->hSeek h(toEnum 0)(l*p)>>g h>>=putStrLn).take n

Đọc tên tệp và n từ stdin.

Làm thế nào nó hoạt động:

main=do
  f<-getLine                   -- read file name from stdin
  n<-readLn                    -- read n from stdin
  h<-openFile f ReadMode       -- open the file
  l<-(\x->1+sum[1|_<-x])<$>g h -- read first line and bind l to it's length +1
                               -- sum[1|_<-x] is a custom length function
                               -- because of type restrictions, otherwise I'd have
                               -- to use "toInteger.length"
  s<-hFileSize h               -- get file size
  generate(shuffle[0..div s l-1])>>=
                               -- shuffle all possible line numbers 
  mapM (\->p  ...  ).take n    -- for each of the first n shuffled line numbers 
     hSeek h(toEnum 0).(l*p)>> -- jump to that line ("toEnum 0" is short for "AbsoluteSeek")
     g h>>=                    -- read a line from current position
     putStrLn                  -- and print

Phải mất rất nhiều thời gian và bộ nhớ để chạy chương trình này cho các tệp có nhiều dòng, vì một shufflechức năng không hiệu quả khủng khiếp .

Chỉnh sửa: Tôi đã bỏ lỡ phần "ngẫu nhiên mà không thay thế" (cảm ơn @feersum vì đã chú ý!).


Đá Haskell :)

1
Làm thế nào để tránh chọn một dòng đã được chọn?
frageum

@feersum: oh, tôi đã bỏ lỡ phần đó. Đã sửa.
nimi

Tôi thấy stackoverflow.com/questions/13779630/ Lời là hơi dài dòng!

1
Có lẽ nên có một thách thức riêng về lấy mẫu mà không cần thay thế trong không gian nhỏ.

3

PowerShell v2 +, 209 byte

param($a,$n)
$f=New-Object System.IO.FileStream $a,"Open"
for(;$f.ReadByte()-ne10){$l++}
$t=$f.Length/++$l-1
[byte[]]$z=,0*$l
0..$t|Get-Random -c $n|%{$a=$f.Seek($l*$_,0);$a=$f.Read($z,0,$l-1);-join[char[]]$z}

Lấy đầu vào $alà tên tệp và $nnhư số dòng. Lưu ý rằng $aphải là tên tệp đường dẫn đầy đủ và được coi là mã hóa ANSI.

Sau đó chúng tôi xây dựng một FileStreamđối tượng mới và bảo nó truy cập tệp $avới Openđặc quyền.

Các forvòng lặp .Read()là thông qua dòng đầu tiên cho đến khi chúng ta đánh một \nnhân vật, incrementing line-chiều dài của chúng tôi truy cập mỗi nhân vật. Sau đó, chúng tôi đặt $tbằng kích thước của tệp (nghĩa là luồng dài bao nhiêu) chia cho bao nhiêu ký tự trên mỗi dòng (cộng với một ký tự để đếm số đầu cuối), trừ đi một (vì chúng tôi không có chỉ mục). Sau đó, chúng tôi xây dựng bộ đệm của chúng tôi $zcũng là chiều dài dòng.

Dòng cuối cùng xây dựng một mảng động với ..toán tử phạm vi. 1 Chúng tôi sắp xếp mảng đó Get-Randomvới một -Count $nđể chọn ngẫu nhiên các $nsố dòng mà không lặp lại. Những con số may mắn được dẫn vào một vòng lặp với |%{...}. Mỗi lần lặp chúng ta .Seekđến một vị trí cụ thể, và sau đó .Readtrong các ký tự có giá trị của một dòng, được lưu trữ vào $z. Chúng tôi đúc lại $zdưới dạng một mảng char và -joinnó cùng nhau, để lại chuỗi kết quả trên đường ống và đầu ra được ẩn ở cuối chương trình.

Về mặt kỹ thuật, chúng ta nên kết thúc bằng một $f.Close()cuộc gọi để đóng tệp, nhưng chi phí đó là byte! : p

Thí dụ

a.txt:
a0000000000000000000000000000000000000000000000001
a0000000000000000000000000000000000000000000000002
a0000000000000000000000000000000000000000000000003
a0000000000000000000000000000000000000000000000004
a0000000000000000000000000000000000000000000000005
a0000000000000000000000000000000000000000000000006
a0000000000000000000000000000000000000000000000007
a0000000000000000000000000000000000000000000000008
a0000000000000000000000000000000000000000000000009
a0000000000000000000000000000000000000000000000010

PS C:\Tools\Scripts\golfing> .\read-n-random-lines.ps1 "c:\tools\scripts\golfing\a.txt" 5
a0000000000000000000000000000000000000000000000002 
a0000000000000000000000000000000000000000000000001 
a0000000000000000000000000000000000000000000000004 
a0000000000000000000000000000000000000000000000010 
a0000000000000000000000000000000000000000000000006 

1 Về mặt kỹ thuật, các phương tiện này, chúng tôi chỉ có thể hỗ trợ tối đa 50.000 dòng, vì đó là phạm vi lớn nhất có thể được tự động tạo ra theo cách này. : - / Nhưng, chúng ta không thể chỉ lặp một lần Get-Randomlệnh $n, loại bỏ trùng lặp mỗi vòng lặp, vì điều đó không mang tính quyết định ...


2

Python 3, 146 139 byte

from random import*
i=input
f=open(i())
l=len(f.readline())
[(f.seek(v*l),print(f.read(l)))for v in sample(range(f.seek(0,2)//l),int(i()))]
#print is here^

Đầu vào: [tên tệp] \ n [dòng] \ n

Giải pháp này đã đánh cắp rất nhiều từ @pppery nhưng chỉ là python3.5 và là một chương trình hoàn chỉnh.

Chỉnh sửa: Cảm ơn @Mego cho phạm vi nội tuyến và khả năng tương thích python3.x. Edit2: Làm rõ nơi in là vì tôi nhận được hai bình luận về nó. (Nhận xét rõ ràng không phải là một phần của mã hoặc số byte.)


Cảm ơn bạn! Phần nào là trăn 3.5?

2
r=range(f.seek(0,2)//l)sẽ hoạt động, giúp loại bỏ 3 byte và loại bỏ nhu cầu 3,5. Thậm chí tốt hơn, cạo thêm 3 byte bằng cách nội tuyến rangecuộc gọi trong samplecuộc gọi. Ngoài ra, đây không phải là một chương trình hoàn chỉnh - bạn cần thực sự in danh sách.
Mego

@Lembik: Đó là 3,5 chỉ vì tôi đã sử dụng r=[*range(f.seek(0,2)//l)]vì tôi nghĩ tôi không thể samplelà máy phát điện. Hóa ra tôi có thể. @Mega: Nó hoàn thành bởi vì nó in một dòng trong phạm vi hiểu danh sáchprint(f.read(l))
Alexander Nigl

Bạn cần một tuyên bố in mặc dù.

in là trong danh sách hiểu.
Alexander Nigl

2

Lua, 126 122

r=io.read;f=io.open(r())c=2+f:read():len()for i=1,r()do f:seek("set",c*math.random(0,f:seek("end")/c-1))print(f:read())end

Sử dụng 2 byte để ngắt dòng. Thay đổi 2 thành 1 thành 1. Tôi chỉ có 2 vì đó là những gì tệp thử nghiệm của tôi có.

Có bản thân tôi dưới mục PHP, nhưng vẫn ở vị trí thứ 2 (hiện tại). Nguyền rủa bạn, Ruby nhập!


1
Lua là ngôn ngữ lập trình đầu tiên tôi học được và thậm chí với tất cả những gì tôi đã học kể từ đó, nó vẫn là ngôn ngữ yêu thích của tôi. Nó rất linh hoạt để dễ viết.
Blab

2

Bash (tốt, coreutils), 100 byte

n=`head -1 $2|wc -c`;shuf -i0-$[`stat -c%s $2`/$n] -n$1|xargs -i dd if=$2 bs=$n skip={} count=1 2>&-

Giải trình

Điều này tránh đọc toàn bộ tập tin bằng cách sử dụng dd trích xuất các phần của tệp mà chúng ta cần mà không đọc toàn bộ tệp, thật không may, nó kết thúc khá lớn với tất cả các tùy chọn chúng ta phải chỉ định:

iflà tệp đầu vào
bscó kích thước khối (ở đây chúng tôi đặt nó $nlà độ dài của dòng đầu tiên
skipđược đặt thành các số nguyên ngẫu nhiên được trích xuất từ shufvà tương đương với ibsgiá trị bỏ qua skip* ibsbyte
countsố ibsphần có độ dài cần trả về
status=noneđể loại bỏ thông tin thường xuất ra bởidd

Chúng tôi nhận được độ dài dòng sử dụng head -1 $2|wc -cvà kích thước tập tin với stat -c%s $2.

Sử dụng

Lưu ở trên file.shvà chạy bằng cách sử dụng file.sh n filename.

Thời gian

time ~/randlines.sh 4 test.txt
9412647
4124435
7401105
1132619

real    0m0.125s
user    0m0.035s
sys     0m0.061s

so với

time shuf -n4 test.txt
1204350
3496441
3472713
3985479

real    0m1.280s
user    0m0.287s
sys     0m0.272s

Lần trên cho một tệp 68MiB được tạo bằng cách sử dụng seq 1000000 9999999 > test.txt.

Cảm ơn @PeterCordes cho mẹo -1 của anh ấy!


1
Tôi luôn thích một câu trả lời bash nhưng bạn có thể giải thích làm thế nào điều này không đọc toàn bộ tập tin?

2
@Lembik thêm lời giải thích!
Dom Hastings

1
Bạn có thể bs=thay vì ibs=, vì thiết lập obslà tốt. Tôi đoán bạn không thể thay thế if=$2bằng <$2mặc dù, vì đây vẫn xargslà dòng lệnh. \<$2cũng không hoạt động (xargs sử dụng exec trực tiếp, không có shell).
Peter Cordes

Tôi hy vọng điều này không quá nhiều nhưng tôi rất thích câu trả lời này :) Chỉ cần thử nghiệm nó với tệp 1GB.

1
re: redirect stderr sang stdin: Bạn cũng có thể đóng stderr với 2>&-, do đó, không có nguy cơ đầu ra đi bất cứ đâu (ví dụ: nếu stdin tình cờ là một mô tả tệp đọc-ghi). Nó hoạt động với GNU dd: Nó vẫn tạo ra nó stdouttrước khi thử và không ghi vào stderr.
Peter Cordes

1

Python 3 - 161 160 149 byte

from random import*;
def f(n,g):f=open(g);l=len(f.readline());r=list(range(f.seek(0,2)/l));shuffle(r);[(f.seek(v*l),print(f.read(l)))for v in r[:k]]

Mã này định nghĩa một hàm được gọi là như f(10,'input.txt')


1
Thử thách đòi hỏi một chương trình đầy đủ, vì vậy tôi e rằng định nghĩa hàm là không đủ.
nimi

Để tiết kiệm một byte loại bỏ không gian giữa nhập và *.
mriklojn

1
@nimi Yêu cầu một chương trình đầy đủ cho thử thách này dường như được ghi đè một cách tự nhiên các quy tắc định dạng mã mặc định
pppery

@ppperry: vâng, có thể, nhưng đó chỉ là như vậy.
nimi

Để có được độ dài của tệp bạn có thể f.seek (0,2) , điều đó làm cho việc nhập os và os.stat trở nên lỗi thời.
Alexander Nigl

1

C # 259 byte không trùng lặp

class Program{static void Main(string[]a){int c=Convert.ToInt32(a[1]);var h=File.ReadLines(a[0]);HashSet<int>n=new HashSet<int>();while(n.Count<c)n.Add(new Random().Next(0,h.Count()));for(;c>0;c--)Console.WriteLine(h.Skip(n.ElementAt(c-1)).Take(1).First());}}

Bị đánh cắp

class Program{static void Main(string[] a)
{
        int c = Convert.ToInt32(a[1]);
        var h = File.ReadLines(a[0]);
        HashSet<int> n = new HashSet<int>();
        while (n.Count < c)
            n.Add(new Random().Next(0, h.Count()));           
        for (; c > 0; c--)
            Console.WriteLine(h.Skip(n.ElementAt(c-1)).Take(1).First());
    }
}

File.ReadLines là lười biếng. Điều này có lợi ích bổ sung rằng tất cả các dòng có thể có chiều dài khác nhau.

Chạy nó sẽ là:

sample.exe a.txt 10000

C # 206 byte có trùng lặp

class Program{static void Main(string[]a){var n=new Random();int c=Convert.ToInt32(a[1]);var h=File.ReadLines(a[0]);for(;c>0;c--)Console.WriteLine(h.Skip((int)(n.NextDouble()*h.Count())).Take(1).First());}}

Bị đánh cắp

class Program
{
    static void Main(string[] a)
    {
        Random n = new Random();
        int c = Convert.ToInt32(a[1]);
        var h = File.ReadLines(a[0]);
        for (; c > 0; c--)
            Console.WriteLine(h.Skip((int)(n.NextDouble()*h.Count())).Take(1).First());
    }
}

Tôi không hoàn toàn làm theo giải pháp của bạn. Nếu tất cả các dòng có độ dài khác nhau thì nhiệm vụ là không thể. Ngoài ra, làm thế nào bạn được lấy mẫu ngẫu nhiên mà không thay thế chính xác? Tôi xin lỗi C # của tôi không đủ tốt.

@Lembik Bạn nói đúng, tôi đã không nghĩ về các bản sao. Và tôi có thể đếm số lượng dòng và trích xuất dòng bằng vải lanh, đó là lý do tại sao các dòng có thể thay đổi chiều dài.
Master 117

Nhưng bạn phải nhảy đến một vị trí trong tệp chỉ biết số dòng phải không? Bạn không thể biết đó là nơi trừ khi tất cả các dòng có cùng độ dài.

@Lembik File.ReadLines ("pathToFile") tạo ra một phép liệt kê lười biếng trên tất cả các dòng của tệp, File.ReadLines ("pathToFile"). ElementAt (19) trả về dòng thứ 19 của tệp. Kinda giống như một bản đồ của tất cả các Linestarts.
Master 117

Tôi không nghĩ rằng liệt kê lười biếng nhảy (hoặc tìm kiếm) trong tập tin đáng buồn. Vì vậy, nó không phù hợp với các quy tắc hiện nay.

1

Python (141 byte)

Giữ mỗi dòng có xác suất bằng nhau, sử dụng với đường ống quá. Nó không trả lời bỏ qua giới hạn trước của câu hỏi mặc dù ...

Cách sử dụng cat largefile | python randxlines.py 100hoặc python randxlines 100 < largefile(như @petercordes đã chỉ ra)

import random,sys
N=int(sys.argv[1])
x=['']*N
for c,L in enumerate(sys.stdin):
    t=random.randrange(c+1)
    if(t<N):x[t] = L
print("".join(x))

3
Toàn bộ vấn đề của câu hỏi này là bạn phải tìm kiếm trong luồng đầu vào. Có lẽ bạn nên nói rằng đó là một phần của những hạn chế của câu hỏi mà bạn bỏ qua (mặc dù cách sử dụng ví dụ đọc từ ống dẫn cho thấy khá rõ). Đọc từ stdin với python ./randxlines.py 100 < largefilesẽ tốt cho một câu trả lời thích hợp, mặc dù: trong trường hợp đó stdinsẽ có thể tìm kiếm được.
Peter Cordes
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.