2011-04-03 22 views
8

मैं अपनी कक्षा के लिए "शब्दकोश" पर काम कर रहा हूं। मैं एक पूर्णांक सरणी NumOfWordsInFile[] कहा जाता है जहां NumOfWordsInFile[0] कितने शब्द a.txt में हैं से मेल खाती है और NumOfWordsInFile[25] Z.txt कोलंबे स्विच स्टेटमेंट से कैसे बचें? सी ++

यह अब जैसा कि मैंने पत्र के 26 अलग अलग परिस्थितियों के लिए एक बड़ा स्विच मेल खाती है। मेरे पास AddWord(string word) नामक फ़ंक्शन है। AddWord को पास किए गए शब्द का पहला अक्षर मिलता है और इसे उपयुक्त .txt फ़ाइल में डाल देता है। अब समस्या है। प्रत्येक बार A.txt में एक शब्द जोड़ा जाता है, मुझे NumOfWordsInFile[0] को 1 से बढ़ाना चाहिए। ऐसा करने का एकमात्र तरीका मैं इन विशाल स्विच के साथ कर सकता हूं। मेरे पास एक deleteWord फ़ंक्शन भी है जो शब्द हटा दिए जाने पर NumOfWordsInFile[] को कम करता है। अब मैं दो 26 मामले स्विच नहीं करना चाहता हूं लेकिन समस्या यह है कि मुझे नहीं पता कि यह और कैसे करना है। अब मैं डिलीट फ़ंक्शन के लिए वही काम कर सकता हूं लेकिन मैं वास्तव में कोड के सैकड़ों और लाइनों को नहीं देखना चाहता हूं। क्या ऐसा करने के लिए इससे अच्छा तरीका है? AddWord समारोह में स्विच के

नमूना:

case 'w': 
    if (numOfWordsInFile[22] < maxWordsPerFile) { 
     fout.open(fileName.data(), ios::app); 
     fout << word << " " << endl; 
     numOfWordsInFile[22]++; 
     if (totalWordsInDict < maxWordsInDict) { 
      totalWordsInDict++; 
     } 
     return(Dictionary::success); 
    } else { 
     return(Dictionary::failure); 
    } 

case 'x': 
    if (numOfWordsInFile[23] < maxWordsPerFile) { 
     fout.open(fileName.data(),ios::app); 
     fout << word << " " << endl; 
     numOfWordsInFile[23]++; 
     if (totalWordsInDict < maxWordsInDict) { 
      totalWordsInDict++; 
     } 
     return(Dictionary::success); 
    } else { 
     return(Dictionary::failure); 
    } 

हटाएं कार्य करते हैं।

bool Dictionary::DeleteAWord(string word) 
{ 
    ofstream fout; 
    ifstream fin; 
    string x; 
    string fileName="#.txt"; 
    int count=0; 
    vector <string> words; 
    bool deleted=false; 

    fileName[0]=toupper(word[0]); 
    fin.open(fileName.data()); //makes the file depending on the first letter of the argument "word" 

    while (fin >> x) 
    { 
     words.push_back(x); 
     count++;//number of elements in vector 
    } 
    if (SearchForWord(x)) 
    { 
     for (;count > 0; count--) 
     { 
      if (words[count-1] == word) 
      { 
       // cout << "Found word " << word << " during search, now deleting" << endl; 
       words.erase(words.begin()+(count-1)); 
       deleted = true; 

       /* 
        This clearly doesn't work and is what I need help with, I know why it 
        doesn't work but I don't know how to make it better than having another 
        huge switch. 
       */ 
       numOfWordsInFile[toupper(word[0])]--; 
       /* 

       */ 

       totalWordsInDict--; 
       fin.close(); 
      } 
     } 

     if (deleted) 
     { 
      fout.open(fileName.data()); 
      for (int i = 0; i < words.size(); i++) 
       fout << words[i] << endl; 
      return(Dictionary::success); 
     } 
     return(Dictionary::failure); 
    } 
    return(Dictionary::failure); 
} 
+0

आपके पास आपका जवाब है। आप जो चाहते हैं उसे पूरा करने के लिए अक्षर ए-जेड के संगत लेआउट का उपयोग करने पर बहुत अधिक सहमत हैं (अच्छे कारण के लिए)। जब तक आप केवल अंग्रेज़ी वर्णों का उपयोग कर रहे हों (जैसा कि रेडएक्स ने बताया), यह सबसे अच्छा समाधान है। –

उत्तर

3

वर्ण मूल रूप से नंबर दिए गए हैं। 'ए' 9 7 है, 'बी' 98 है और इसी तरह। सबसे आसान तरीका है बस इस तरह, प्रत्येक मामले के लिए बार-बार एक समारोह में रहते हैं सकता है numOfWordsInFile[current_char - 'a'] के साथ हर numOfWordsInFile[n] और पूरे कोड को बदलने के लिए है:

int AddWord(char current_char) { 
    if(numOfWordsInFile[current_char - 'a']<maxWordsPerFile){ 
    fout.open(fileName.data(),ios::app); 
    fout<<word<<" "<<endl; 
    numOfWordsInFile[current_char - 'a']++; 
     if(totalWordsInDict<maxWordsInDict){ 
     totalWordsInDict++; 
    } 
    return(Dictionary::success); 
    }else{ 
    return(Dictionary::failure); 
    } 
    } 

अधिक सामान्य समाधान के लिए हैश नक्शे और समारोह संकेत के बारे में पढ़ा है (जब, उदाहरण के लिए, प्रत्येक चार के लिए आप एक अलग समारोह आवंटित करने के लिए चाहते हो सकता है।

1

यदि आपकी फ़ाइल a.txt है, अपने सरणी सूचकांक होना 'A' - 'A' (= 0), अगर फाइल B.txt है, सरणी सूचकांक 'B' - 'A' हो जाने (= 1), आदि

3
if(numOfWordsInFile[letter - 'A']<maxWordsPerFile){ 
fout.open(fileName.data(),ios::app); 
fout<<word<<" "<<endl; 
numOfWordsInFile[letter - 'A']++; 
if(totalWordsInDict<maxWordsInDict){ 
    totalWordsInDict++; 
} 
return(Dictionary::success); 
}else{ 
return(Dictionary::failure); 
} 

यह केवल तभी काम करेगा यदि आपके पास केवल आपके उपयोग-मामले में अंग्रेजी पत्र है।

7

बस एक बहुत तेज़ लग रहा है, ऐसा लगता है कि आप सामान करने के लिए वर्णमाला में अक्षर की स्थिति का उपयोग कर रहे हैं।

int letter = (int)(ActualLetter - 'a'); 

if(numOfWordsInFile[letter]<maxWordsPerFile){ 
fout.open(fileName.data(),ios::app); 
fout<<word<<" "<<endl; 
numOfWordsInFile[letter]++; 
if(totalWordsInDict<maxWordsInDict){ 
    totalWordsInDict++; 
} 
return(Dictionary::success); 
}else{ 
return(Dictionary::failure); 
} 

ActualLetter कुछ की तरह 'एक' है, उदाहरण के लिए,:

आप एक बयान है कि लगता है कि के साथ अपने सभी स्विच बयान बदल सकते थे। , आप सी ++ विधि आप के लिए प्रेषण के लिए बहुरूपता का उपयोग कर सकते

switch (letter) 
{ 
    case 'a': 
     LetterA(); 
     break; 

    case 'b': 
     LetterB(); 
     break; 

    ... 
} 

या और भी बेहतर:

एक संबंधित नोट पर, भविष्य में यदि आप वास्तव में बड़ी स्विच बयान है, कार्यों में कोड encapsulating पर विचार विशिष्ट व्युत्पन्न वर्ग के आधार पर हैं:

class BaseLetter 
{ 
    ... 
public: 
    virtual void DoStuff() = 0; 
}; 

class LetterA : public BaseLetter 
{ 
public: 
    void DoStuff(); 
}; 

class LetterB : public BaseLetter 
{ 
public: 
    void DoStuff(); 
}; 

void Foo(BaseLetter *letter) 
{ 
    // Use dynamic dispatch to figure out what to do 
    letter->DoStuff(); 
} 

बस इतना ध्यान रखें, गतिशील प्रेषण एक (हल्का) प्रदर्शन हिट है, और इसके बाद के संस्करण की बहुत बुरी जगह वास्तव में इसका इस्तेमाल करने की है। समाधान I, RedX, और अन्य ने पोस्ट किया है आपके विशिष्ट उदाहरण के लिए काफी बेहतर है।

+1

और ऐसे मामलों में जहां आप अतिरिक्त वर्ण (जैसे अंक) जोड़ने का निर्णय लेते हैं, तो आपको केवल उस पंक्ति के साथ पहली पंक्ति को प्रतिस्थापित करना होगा जो एक चरित्र लेता है और एक इंडेक्स नंबर देता है। – swestrup

+0

@ स्वेस्टस्ट्रप: बिल्कुल। यह स्वयं का दोहराना न करने का एक आदर्श उदाहरण है। –

6

सबसे व्यावहारिक वर्ण एन्कोडिंग कि आप C++ या सी का उपयोग कर, जबकि सामना करने के लिए, 'a' को 'z', सन्निहित हैं होने की संभावना हो तो आप में (c - 'a'), जहां cchar आप कर रहे है ऐसा करके बस का उपयोग करने के सरणी सूचकांक प्राप्त कर सकते हैं देखना।

+1

एक गंभीर संभावना है कि आपका बैंक खाता और आपका बीमा रिकॉर्ड एक एन्कोडिंग के साथ संग्रहीत किया जाता है जहां अंग्रेजी वर्णमाला पत्र संगत नहीं होते हैं (ईबीसीडीआईसी)। हालांकि उन प्रणालियों को शायद सबसे अधिक COBOL में प्रोग्राम किया गया है ... – 6502

+0

+1। यह अब तक का सबसे आसान समाधान है। – Maxpm

+0

@ 6502: यह कोई समस्या नहीं है, जब तक आपके सरणी का आकार ('z' - 'a' + 1) हो। आपके पास बीच में कुछ अप्रयुक्त प्रविष्टियां होंगी। सभी सनी चरित्र एन्कोडिंग में 'z'> 'a' है। – MSalters

2

सी ++ में एकल वर्ण वास्तव में केवल उनके ASCII मानों के अनुरूप संख्याएं हैं। आप संख्यात्मक मान प्राप्त करने के लिए एक-दूसरे से अक्षरों को घटा सकते हैं। तो यदि word[0] में अक्षर ए है, तो word[0] - 'A'0 होगा।

तो आप सीधे अपने numOfWordsInFile सरणी को इंडेक्स कर सकते हैं, और आपको बिल्कुल स्विच की आवश्यकता नहीं होगी: numOfWordsInFiled[word[0] - 'A']

ध्यान दें कि 'A' and 'a' में विभिन्न संख्यात्मक मान हैं, इसलिए यदि आप ऊपरी और निचले मामले को मिश्रित कर रहे हैं तो आपको कुछ अतिरिक्त काम करना होगा।

5
struct FileInfo { 
    int NumWords; 
    std::string Filename; 
}; 

std::map<char, FileInfo> TheFiles; 

FileInfo & FI = TheFiles[letter]; 
// Work with FI.NumWords and FI.Filename 

वैकल्पिक रूप से:

std::vector<FileInfo> TheFiles; 
FileInfo & FI = TheFiles[std::tolower(Letter) - 'a']; 
+0

आखिर में एक सायन प्रतिक्रिया: कार्य के लिए सबसे सरल डेटा संरचना * संरचना * डेटा संरचना कितनी सरल है, यह परिभाषित नहीं है, लेकिन इंटरैक्शन (इस कार्य के लिए) कितनी सरल है। उपलब्ध विधियों पर ध्यान केंद्रित, प्रतिनिधित्व बंद करो। –

+1

@Maththieu एम। मेरी इच्छा है। लेकिन "दक्षता" और "चतुरता" की खोज किसी भी प्रोग्रामर करियर के पहले वर्षों में सबकुछ खत्म कर देती है। – Erik

1

यह कैसे पोर्टेबल आप होना चाहते हैं, या पर निर्भर करता है कि कैसे अंतर्राष्ट्रीय। पहले अक्षर एक हो सकता है कि आप संभावना अनदेखी करने के लिए खर्च कर सकते हैं, तो उच्चारण वर्ण, और मान लें कि आप कभी नहीं होंगे एक मेनफ्रेम पर, या कहीं भी अन्यथा जो ईबीसीडीआईसी का उपयोग करता है, तो आप पहले अक्षर को पर एक विशिष्ट मामले में परिवर्तित कर सकते हैं, और सूचकांक प्राप्त करने के लिए से 'ए' या 'ए' (मामले के आधार पर) घटाएं। सी ++ मानक की गारंटी नहीं देता है कि पत्र संगत हैं, और वे ईबीसीडीआईसी में नहीं हैं, न ही किसी भी एन्कोडिंग में जो अक्षरों का उच्चारण करते हैं। कम से कम, आपको यह जांचना होगा कि पहला चरित्र निश्चित रूप से एक पत्र है।

अंतर्राष्ट्रीयकरण समस्या को संभालना मुश्किल है, क्योंकि कोई भी आम तौर पर एन्कोडिंग का उपयोग नहीं करता है, और एन्कोडिंग में से कुछ मल्टीबाइट हैं। एकल बाइट एन्कोडिंग के लिए, यह मैपिंग टेबल का उपयोग करने के लिए काफी सीधे आगे है; 256 प्रविष्टियों वाली एक तालिका, पहले अक्षर द्वारा अनुक्रमित ( char को हस्ताक्षरित करने के लिए डाली गई), जो आपकी तालिका में इंडेक्स लौटाती है। मल्टीबाइट यूटीएफ -8 की तरह एन्कोडिंग के लिए, समस्या अधिक जटिल है: आप एक यूटीएफ -8 अनुक्रम में प्रारंभिक चरित्र को int, पर अनुवाद कर सकते हैं लेकिन आप लगभग दस लाख या उससे अधिक के मानों के साथ समाप्त हो सकते हैं, और आप एक लाख प्रविष्टियों वाली तालिका नहीं चाहते हैं (जिनमें से अधिकांश पूरी तरह से अप्रासंगिक हैं। "अन्य" के लिए 27 वें प्रविष्टि को जोड़ने का एक आसान समाधान हो सकता है। (यह "2" जैसे "शब्द" को भी पकड़ लेगा।)

एक ऐसा करने के लिए बहुत पोर्टेबल तरीका होगा:

int mappingTable[256]; 

std::fill_n(mappingTable, 256, 26); 
static char const upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ; 
static char const lower[] = "abcdefghijklmnopqrstuvwxyz; 
for (int i = 0; i < 26; ++ i) { 
    mappingTable[upper[i]] = i; 
    mappingTable[lower[i]] = i; 
} 

जम्मू इंडेक्सिंग से पहले शुरुआती चरित्र को हस्ताक्षर किए गए चार पर डालना न भूलें।

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