2015-09-01 10 views
6

से यादृच्छिक रेखा पढ़ें मेरे पास 5000+ लाइनों वाली एक फ़ाइल है। जब भी मैं अपना प्रोग्राम चलाता हूं, मैं उन पंक्तियों में से किसी एक को चुनने का सबसे प्रभावी तरीका खोजना चाहता हूं। मैं मूल रूप से एक चुनने के लिए यादृच्छिक विधि का उपयोग करना चाहता था (जो मुझे पता था कि 5000 लाइनें थीं)। सोचा कि अक्षम हो सकता है इसलिए मैंने सोचा कि मैं पहली पंक्ति को पढ़ने, फिर इसे शीर्ष से हटाने और इसे नीचे जोड़ने के लिए देखता हूं। लेकिन ऐसा लगता है कि मुझे पूरी फाइल को पढ़ना है और शीर्ष से हटाने के लिए एक नई फाइल बनाना है।एक बड़ी टेक्स्ट फ़ाइल

सबसे प्रभावी तरीका क्या है: यादृच्छिक विधि या नई फ़ाइल विधि?

कार्यक्रम हर 5 मिनट चलाया जाएगा और मैं सी # 4.5

+4

फ़ाइल में एक यादृच्छिक ऑफसेट की तलाश करें, फिर एक न्यूलाइन चरित्र के लिए आगे स्कैन करें। अगली नई लाइन तक डेटा पढ़ें। फ़ाइल के अंत के साथ अपनी सावधानी बरतें। यदि लाइनों में बड़ी लंबाई भिन्नता है तो संभावना एक समान नहीं होगी। ओह, और 5000 नहीं है * वह * बहुत ;-) –

+0

प्रत्येक 100 लाइनों के साथ 50 फाइलों को तोड़ें, फ़ाइल के लिए यादृच्छिक numb 0-50, लाइन के लिए यादृच्छिक रेखा 0-99। ऐसा कहकर, हर 5 मिनट में 5000 लाइनों को पढ़ना अभी भी एक बड़ा मुद्दा नहीं है ... कुशल नहीं, बल्कि असली मुद्दा नहीं। यदि यह ऐप के साथ आपकी एकमात्र समस्या है, तो आप अच्छे हैं :) – Noctis

+0

कुल में फ़ाइल कितनी बड़ी है? – olydis

उत्तर

0

मुझे लगता है बेतरतीब ढंग से 5000+ लाइनों की एक फ़ाइल से एक पंक्ति का चयन करने के लिए है कि लक्ष्य का उपयोग कर रहा हूँ।

इस प्रयास करें:

  1. File.ReadLines (फ़ाइल) का उपयोग कर लाइन गिनती .Count जाओ()।
  2. रेखा गणना को ऊपरी सीमा के रूप में उपयोग करके यादृच्छिक संख्या उत्पन्न करें।
  3. फ़ाइल के साथ फ़ाइल का आलसी पढ़ें। रीडलाइन (फ़ाइल)।
  4. यादृच्छिक संख्या का उपयोग करके इस सरणी से एक रेखा चुनें।

संपादित करें: जैसा कि बताया गया है, फ़ाइल करना। रीडलाइन (फ़ाइल) .toArray() बहुत अक्षम है।

+1

अब तक टिप्पणियों में सुझाई गई सभी चीजों से, यह सबसे अक्षम समाधान होगा। 'फाइल. रीडलाइन' पर आपके दोनों कॉल पूरी फाइल को पढ़ेंगे (कॉल करने के लिए 'ToArray' चरण 3 ** कुछ भी आलसी ** ** बनाता है) - इसके अलावा: हाँ आप सही मानते हैं, क्योंकि यह वही है जो उसने – olydis

+0

ओह से पूछा , बिल्कुल सही। मैं ToArray() विधि कॉल को हटा दूंगा। लेकिन आप यह भी सही हैं कि वैसे भी यह वास्तव में सबसे कुशल विधि नहीं है। –

+1

फिर भी आप फ़ाइल को एक से अधिक बार पढ़ते हैं: 'File.ReadAllLines' तेज़ होगा, जैसे http://stackoverflow.com/questions/3745934/read-random-line-from-a-file-c-sharp – olydis

2

.NET 4. * में, फ़ाइल की एक पंक्ति को सीधे एक्सेस करना संभव है।

string line = File.ReadLines(FileName).Skip(X).First(); 

पूर्ण उदाहरण: उदाहरण के लिए, लाइन एक्स पाने के लिए

var fileName = @"C:\text.txt" 
var file = File.ReadLines(fileName).ToList(); 
int count = file.Count(); 
Random rnd = new Random(); 
int skip = rnd.Next(0, count); 
string line = file.Skip(skip).First(); 
Console.WriteLine(line); 
+2

'फ़ाइल। रीडलाइन (फ़ाइल नाम) .Skip (X)। टेक (1)। फर्स्ट()' को फ़ाइल 'रीडलाइन (फ़ाइल नाम) के लिए सरलीकृत किया जा सकता है .कुप (एक्स)। सबसे पहले() ' – olydis

+0

बिल्कुल, मैं मैंने अपना जवाब अपडेट किया है। धन्यवाद। – randoms

+0

आपका पूरा उदाहरण पूरी फ़ाइल को स्मृति में दो बार पढ़ रहा है। – theB

0

यहाँ @LucasTrzesniewski रों की एक त्वरित कार्यान्वयन प्रश्न के टिप्पणी में प्रस्तावित विधि:

// open the file 
using(FileStream stream = File.OpenRead("yourfile.dat")) 
{ 
    // 1. index all offsets that are the beginning of a line 
    List<Long> lineOffsets = new List<Long>(); 
    lineOffsets.Add(stream.Position); //the very first offset is a beginning of a line! 
    int ch; 
    while((ch = stream.ReadByte()) != -1) // "-1" denotes the end of the file 
    { 
     if(ch == '\n') 
      lineOffsets.Add(stream.Position); 
    } 

    // 2. read a random line 
    stream.Seek(0, SeekOrigin.Begin); // go back to the beginning of the file 
    // set the position of the stream to one the previously saved offsets 
    stream.Position = lineOffsets[new Random().Next(lineOffsets.Count)]; 
    // read the whole line from the specified offset 
    using(StreamReader reader = new StreamReader(stream)) 
    { 
     Console.WriteLine(reader.ReadLine()); 
    } 
} 

मैं डॉन फिलहाल मेरे पास कोई वीएस नहीं है, इसलिए यह अनचाहे है।

+1

यदि आपके पास यूटीएफ -8 जैसे मल्टी-बाइट वर्णों वाली फ़ाइल है (जो प्रति चरित्र 1-6 बाइट्स ले सकती है) और आप जिस ऑफसेट को यादृच्छिक रूप से चुनते हैं, वह उन पात्रों में से एक के बीच में होती है। –

1

फ़ाइल मान देता है इतनी बड़ी है कि आप रैम में फिट करने के लिए खर्च नहीं उठा सकते है। उसके बाद, आप Reservoir Sampling, एक एल्गोरिथ्म अज्ञात, मनमाने ढंग से लंबाई की सूची है कि स्मृति में फिट नहीं हो सकता से बेतरतीब ढंग से उठा संभालने के लिए तैयार किया गया है का उपयोग करना चाहते हैं:

Random r = new Random(); 
int currentLine = 1; 
string pick = null; 
foreach (string line in File.ReadLines(filename)) 
{ 
    if (r.Next(currentLine) == 0) { 
     pick = line; 
    } 
    ++currentLine; 
} 
return pick; 

एक उच्च स्तर पर, जलाशय नमूना एक बुनियादी नियम इस प्रकार है: प्रत्येक आगे की रेखा में सभी पिछली लाइनों को बदलने का 1/एन मौका है।

इस एल्गोरिथ्म थोड़ा unintuitive है। एक उच्च स्तर पर, यह होने लाइन एन से काम करता है वर्तमान में चयनित पंक्ति को बदला के एक 1/एन मौका है। इस प्रकार, लाइन 1 का चयन करने का 100% मौका है, लेकिन 50% बाद में लाइन 2 द्वारा प्रतिस्थापित किया जा रहा है।

मुझे इस एल्गोरिदम को शुद्धता के सबूत के रूप में सबसे आसान माना गया है। तो, प्रेरण द्वारा एक सरल सबूत:

1) बेस मामला: निरीक्षण करके, एल्गोरिथ्म काम करता है, अगर वहाँ 1 लाइन।
2) यदि एल्गोरिदम एन -1 लाइनों के लिए काम करता है, तो एन लाइनों को संसाधित करता है क्योंकि:
3) एन लाइन फ़ाइल के एन -1 पुनरावृत्तियों को संसाधित करने के बाद, सभी एन -1 लाइन समान रूप से संभावना (संभावना 1/(एन -1))।
4) अगले चरण सुनिश्चित करता है कि लाइन एन (1/एन की सम्भावना है, क्योंकि है कि क्या एल्गोरिथ्म स्पष्ट रूप से इसे प्रदान करती है, और यह अंतिम यात्रा है), के लिए सभी पिछले लाइनों की संभावना को कम करने:

1/(N-1) * (1-(1/N)) 
1/(N-1) * (N/N-(1/N)) 
1/(N-1) * (N-1)/N 
(1*(N-1))/(N*(N-1)) 
1/N 

यदि आप जानते हैं कि फ़ाइल में कितनी लाइनें पहले से हैं, तो यह एल्गोरिदम आवश्यक से अधिक महंगा है, क्योंकि यह हमेशा पूरी फ़ाइल को पढ़ता है।

+0

यह भी देखें http://stackoverflow.com/questions/3745934/read-random-line-from-a-file-c-sharp – Duncan

+0

हाँ, [tvanfosson का उत्तर] (http://stackoverflow.com/a/3745973/ 18192) वही है। – Brian

संबंधित मुद्दे