2011-10-06 19 views
5

से सबस्ट्रिंग के संयोजन उत्पन्न करना मैं किसी दिए गए शब्द के लिए सभी संभावित अक्षरों संयोजन उत्पन्न करने का प्रयास कर रहा हूं। एक अक्षर के बारे में पहचानने की प्रक्रिया यहां प्रासंगिक नहीं है, लेकिन यह उन सभी संयोजनों का निर्माण है जो मुझे समस्या दे रही हैं। मुझे लगता है कि मुझे लगता है कि कुछ लाइनों में रिकर्सिवली करना संभव है (हालांकि कोई अन्य तरीका ठीक है), लेकिन मुझे इसे काम करने में परेशानी हो रही है। क्या कोई मदद कर सकता है?स्ट्रिंग

// how to test a syllable, just for the purpose of this example 
    bool IsSyllable(string possibleSyllable) 
    { 
     return Regex.IsMatch(possibleSyllable, "^(mis|und|un|der|er|stand)$"); 
    } 

    List<string> BreakIntoSyllables(string word) 
    { 
     // the code here is what I'm trying to write 
     // if 'word' is "misunderstand" , I'd like this to return 
     // => {"mis","und","er","stand"},{ "mis","un","der","stand"} 
     // and for any other combinations to be not included 
    } 
+0

आपको अपने अक्षरों को सूचीबद्ध करने के लिए ट्री का उपयोग करना चाहिए। या आप नाइवर समाधान का उपयोग कर सकते हैं :-) – xanatos

उत्तर

4

इस के साथ शुरुआत करें Concat

misunderstand-results

के साथ शुरू है कि मदद करता है कम से कम?


संपादित करें: मैं थोड़ा आगे इस समस्या के बारे में सोचा एक प्रश्नों की इस जोड़ी के साथ आया था:

Func<string, IEnumerable<string[]>> splitter = null; 
splitter = 
    t => 
     from n in Enumerable.Range(1, t.Length - 1) 
     let s = t.Substring(0, n) 
     let e = t.Substring(n) 
     from g in (new [] { new [] { e } }).Concat(splitter(e)) 
     select (new [] { s }).Concat(g).ToArray(); 

var query = 
    from split in (new [] { new [] { word } }).Concat(splitter(word)) 
    where split.All(part => isSyllable(part)) 
    select split; 

अब query वापसी इस:

misunderstanding-results2

मुझे जानते हैं अगर यह अब इसे दबाया गया है।

+0

धन्यवाद, यह आशाजनक प्रतीत होता है लेकिन यह मुझे वर्तमान में एक संकलन त्रुटि दे रहा है - "सिस्टम। चयन। जेनेरिक। IEnumerable 'में' स्टार्टविथ 'की परिभाषा नहीं है और कोई एक्सटेंशन विधि नहीं है' के साथ शुरू'" । – mikel

+0

@ मिकेल - आह, इसके बारे में खेद है। मैंने एक प्रतिक्रियाशील फ्रेमवर्क विस्तार विधि का उपयोग किया। जब मैं अपने पीसी पर वापस आऊंगा तो मैं इसे ठीक कर दूंगा। – Enigmativity

+0

@ मिकेल - मैंने मानक ऑपरेटरों का उपयोग करने के लिए क्वेरी बदल दी है। – Enigmativity

3

आम तौर पर इस प्रकार की समस्याओं को Tries का उपयोग करके हल किया जाता है। मैं How to create a trie in c# पर ट्री के कार्यान्वयन का आधार रखूंगा (लेकिन ध्यान दें कि मैंने इसे फिर से लिखा है)।

var trie = new Trie(new[] { "un", "que", "stio", "na", "ble", "qu", "es", "ti", "onable", "o", "nable" }); 
//var trie = new Trie(new[] { "u", "n", "q", "u", "e", "s", "t", "i", "o", "n", "a", "b", "l", "e", "un", "qu", "es", "ti", "on", "ab", "le", "nq", "ue", "st", "io", "na", "bl", "unq", "ues", "tio", "nab", "nqu", "est", "ion", "abl", "que", "stio", "nab" }); 

var word = "unquestionable"; 

var parts = new List<List<string>>(); 

Split(word, 0, trie, trie.Root, new List<string>(), parts); 

// 

public static void Split(string word, int index, Trie trie, TrieNode node, List<string> currentParts, List<List<string>> parts) 
{ 
    // Found a syllable. We have to split: one way we take that syllable and continue from it (and it's done in this if). 
    // Another way we ignore this possible syllable and we continue searching for a longer word (done after the if) 
    if (node.IsTerminal) 
    { 
     // Add the syllable to the current list of syllables 
     currentParts.Add(node.Word); 

     // "covered" the word with syllables 
     if (index == word.Length) 
     { 
      // Here we make a copy of the parts of the word. This because the currentParts list is a "working" list and is modified every time. 
      parts.Add(new List<string>(currentParts)); 
     } 
     else 
     { 
      // There are remaining letters in the word. We restart the scan for more syllables, restarting from the root. 
      Split(word, index, trie, trie.Root, currentParts, parts); 
     } 

     // Remove the syllable from the current list of syllables 
     currentParts.RemoveAt(currentParts.Count - 1); 
    } 

    // We have covered all the word with letters. No more work to do in this subiteration 
    if (index == word.Length) 
    { 
     return; 
    } 

    // Here we try to find the edge corresponding to the current character 

    TrieNode nextNode; 

    if (!node.Edges.TryGetValue(word[index], out nextNode)) 
    { 
     return; 
    } 

    Split(word, index + 1, trie, nextNode, currentParts, parts); 
} 

public class Trie 
{ 
    public readonly TrieNode Root = new TrieNode(); 

    public Trie() 
    { 
    } 

    public Trie(IEnumerable<string> words) 
    { 
     this.AddRange(words); 
    } 

    public void Add(string word) 
    { 
     var currentNode = this.Root; 

     foreach (char ch in word) 
     { 
      TrieNode nextNode; 

      if (!currentNode.Edges.TryGetValue(ch, out nextNode)) 
      { 
       nextNode = new TrieNode(); 
       currentNode.Edges[ch] = nextNode; 
      } 

      currentNode = nextNode; 
     } 

     currentNode.Word = word; 
    } 

    public void AddRange(IEnumerable<string> words) 
    { 
     foreach (var word in words) 
     { 
      this.Add(word); 
     } 
    } 
} 

public class TrieNode 
{ 
    public readonly Dictionary<char, TrieNode> Edges = new Dictionary<char, TrieNode>(); 
    public string Word { get; set; } 

    public bool IsTerminal 
    { 
     get 
     { 
      return this.Word != null; 
     } 
    } 
} 

word स्ट्रिंग आप रुचि रखते parts, में संभव अक्षरों की सूचियों की सूची में शामिल होंगे (यह शायद यह एक List<string[]> बनाने के लिए सही होगा रहे है, लेकिन यह parts.Add(new List<string>(currentParts)); की यह करने के लिए काफी आसान है। इसके बजाय parts.Add(currentParts.ToArray()); लिख सकते हैं और सभी List<List<string>>List<string[]> लिए बदल जाते हैं।

मैं Enigmativity प्रतिक्रिया का एक प्रकार जोड़ देंगे thas theretically तेजी से उसकी तुलना में है, क्योंकि यह गलत अक्षरों तुरंत बजाय बाद छानने उन्हें बाद में। आप इसे पसंद करते हैं, तो आपको चाहिए की निरस्त कर देती है उसे एक +1 दें, क्योंकि उसके विचार के बिना, यह भिन्न है टी संभव नहीं होगा। लेकिन ध्यान दें कि यह अभी भी एक हैक है।

 from n in Enumerable.Range(1, t.Length - 1) 
     let s = t.Substring(0, n) 
     where isSyllable(s) 

हम की लंबाई के लंबाई 1 से एक शब्द के सभी संभव अक्षरों, गणना: "सही" समाधान Trie (रों) एक व्याख्या का उपयोग कर :-)

Func<string, bool> isSyllable = t => Regex.IsMatch(t, "^(un|que|stio|na|ble|qu|es|ti|onable|o|nable)$"); 

Func<string, IEnumerable<string[]>> splitter = null; 
splitter = 
    t => 
     (
     from n in Enumerable.Range(1, t.Length - 1) 
     let s = t.Substring(0, n) 
     where isSyllable(s) 
     let e = t.Substring(n) 
     let f = splitter(e) 
     from g in f 
     select (new[] { s }).Concat(g).ToArray() 
     ) 
     .Concat(isSyllable(t) ? new[] { new string[] { t } } : new string[0][]); 

var parts = splitter(word).ToList(); 

में है शब्द -1 और जांचें कि यह एक अक्षर है या नहीं। हमने सीधे गैर-अक्षरों को बुझाया। एक अक्षर के रूप में पूरा शब्द बाद में जांच की जाएगी।

 let e = t.Substring(n) 
     let f = splitter(e) 

हम स्ट्रिंग

 from g in f 
     select (new[] { s }).Concat(g).ToArray() 

के शेष भाग के अक्षरों खोज और हम "वर्तमान" शब्दांश के साथ पाया अक्षरों श्रृंखला। ध्यान दें कि हम कई बेकार सरणी बना रहे हैं। अगर हम परिणाम के रूप में IEnumerable<IEnumerable<string>> स्वीकार करते हैं, तो हम इसे ToArray निकाल सकते हैं।

(हम कई कतारें लग पुनर्लेखन कर सकता है, जैसे

 from g in splitter(t.Substring(n)) 
     select (new[] { s }).Concat(g).ToArray() 

, कई let को हटाने, लेकिन हम स्पष्टता के लिए यह काम नहीं चलेगा)

और हमने पाया अक्षरों के साथ "वर्तमान" शब्दांश श्रेणीबद्ध ।

 .Concat(isSyllable(t) ? new[] { new string[] { t } } : new string[0][]); 

यहाँ हम क्वेरी पुनर्निर्माण एक छोटे से इतना को यह Concat का उपयोग नहीं और खाली सरणियों बना सकते हैं, लेकिन यह होगा एक छोटे से जटिल

में (हम एक isSyllable(t) ? new[] { new string[] { t } }.Concat(oldLambdaFunction) : oldLambdaFunction के रूप में पूरे लैम्ब्डा समारोह को फिर से लिखने सकता है) अंत, यदि पूरा शब्द एक अक्षर है, तो हम पूरे शब्द को एक अक्षर के रूप में जोड़ते हैं।

var word = "misunderstand"; 

Func<string, bool> isSyllable = 
    t => Regex.IsMatch(t, "^(mis|und|un|der|er|stand)$"); 

var query = 
    from i in Enumerable.Range(0, word.Length) 
    from l in Enumerable.Range(1, word.Length - i) 
    let part = word.Substring(i, l) 
    where isSyllable(part) 
    select part; 

यह रिटर्न: अन्यथा हम एक खाली सरणी (ताकि कोई Concat)

0

आपको ईमानदार होने के लिए इसे स्केल करने में समस्या हो सकती है, मुझे यकीन नहीं है कि आपका डेटासेट कितना बड़ा है लेकिन एक सरल पर आधारित समाधान 'क्या यह एक अक्षर है?' आपको प्रत्येक शब्द के लिए अपने 'अक्षर योग्य पहचान' दिनचर्या को लगभग 0 (एन * एन) कॉल करने की आवश्यकता होगी जहां n = शब्द में वर्णों की संख्या (यदि यह अर्थहीन है, तो इसका मतलब है कि यह बड़े डेटासेट के लिए धीमा होने की संभावना है!) । यह पहचान एल्गोरिदम की स्केलेबिलिटी को ध्यान में रखता है जो आप अधिक अक्षरों को जोड़ते समय भी धीमा कर सकते हैं। ।

मुझे पता है कि आपने यह कहने के लिए अपनी प्रक्रिया कहा है कि एक अक्षर क्या है या नहीं प्रासंगिक है, लेकिन कहें कि आप इसे स्वत: पूर्णता की तरह काम करने के लिए बदल सकते हैं, यानी एक अक्षर की शुरुआत में पास करें और यह आपको सभी को बताए इस बिंदु से संभव अक्षर जो अधिक स्केलेबल होंगे। यदि प्रदर्शन हाथ से बाहर हो जाता है तो उसे trie के साथ बदलने की एक नज़र डालें।

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

  • कोई संबंधित समस्या नहीं^_^