2013-05-10 82 views
0

我有一個擴展的一個問題已經問here查找字符串C#字符的最發生,返回最長的復現字符的字符串

但是我想回到最長的一組名單重新確定原始字符串中的字符,而不是它們相對計數的字符列表,按照最高排序。

我相當精通的聯繫,但從來沒有翻過來在字符串中查詢字符類型的實例,並認爲有人可以給我一個提示,以幫助我理解LINQ的具體使用情況...

感謝

+0

ie。爲「abbbbccd」返回「bbbb」 – matthewbaskey 2013-05-10 22:15:57

+0

你能否提供一個例子。更好地理解這個問題會有所幫助。 – arunlalam 2013-05-10 22:26:49

+1

如果輸入是「abbbbccdb」 - 你希望輸出是「bbbb」還是「bbbbb」? – dugas 2013-05-10 23:00:01

回答

4

我假設你想要的最長的串。例如,對於aabccc你想要

我還假設問題域是Unicode字符的字符串。不幸的是,.NET的System.String是一組代碼單元。要統計或索引Unicode字符,您必須將它們作爲代碼點處理。最簡單的方法是將編碼更改爲UTF-32,因爲每個編碼點有一個int,而編碼點是Unicode字符的數字標識符[一般而言]。

之後,要找到相同字符的最長子序列,您必須遍歷整個序列。運行長度編碼是我用作中間步驟的一種通用方法。在找到最長的子序列的代碼點和長度後,我重新創建它們的一串。

 const string test = "aabccc"; // contains barber pole characters 
     Console.WriteLine(test); 

     var longest = test.ToCodepoints().RunLengthEncode().OrderByDescending(itemCount => itemCount.Item2).First(); 
     var subsequence = String.Concat(Enumerable.Repeat(Char.ConvertFromUtf32(longest.Item1), longest.Item2)); 
     Console.WriteLine(subsequence); 

將字符串轉換爲代碼點相當於轉換爲UTF-32。它可以用System.Text.Encoding方法完成,但最終會產生一個字節數組,然後必須將其轉換爲碼點。這裏是一個IEnumerable,它產生一個int的序列。

public static IEnumerable<int> ToCodepoints(this String s) 
    { 
     var codeunits = s.ToCharArray(); 
     var i = 0; 

     while (i < codeunits.Length) 
     { 
      int codepoint; 
      if (Char.IsSurrogate(codeunits[i])) 
      { 
       codepoint = Char.ConvertToUtf32(codeunits[i], codeunits[i + 1]); 
       i += 2; 
      } 
      else 
      { 
       codepoint = codeunits[i]; 
       i += 1; 
      } 
      yield return codepoint; 
     } 

    } 

運行長度編碼產生的碼點的一個元組(Item1)和相同碼點的每個子序列中運行(Item2)的長度:

public static IEnumerable<Tuple<T, int>> RunLengthEncode<T>(this IEnumerable<T> sequence) 
    { 
     T item = default(T); // value never used 
     int length = 0; 
     foreach (var nextItem in sequence) 
     { 
      if (length == 0) // first item 
      { 
       item = nextItem; 
       length = 1; 
      } 
      else if (item.Equals(nextItem)) // continuing run 
      { 
       length++; 
      } 
      else // run boundary 
      { 
       var run = Tuple.Create(item, length); 
       item = nextItem; 
       length = 1; 
       yield return run; 
      } 
     } 
     if (length > 0) // last run 
     { 
      yield return Tuple.Create(item, length); 
     } 
+0

你能解釋一下'理髮師極人物'的意思嗎,谷歌搜索引發你在理髮店外看到的螺旋柱。我假設你可能指的是管道字符||,但是將第一部分代碼粘貼到控制檯應用程序中會帶來帶有問號的小方塊。請澄清。謝謝。我會繼續你的榜樣。 – matthewbaskey 2013-05-11 09:37:22

+0

Unicode Character'[BARBER POLE](http://www.fileformat.info/info/unicode/char/1f488/index.htm)'(U + 1F488)僅僅是一個由兩個System .Char元素。請參閱(絕對最低限度每個軟件開發人員絕對,肯定必須知道Unicode和字符集)[http://www.joelonsoftware.com/articles/Unicode.html] Joel Spolsky。 (IE)上的Visual Studio和StackOverflow應該顯示該字符正常。其他瀏覽器/系統/字體可能會回落到包含十六進制數字的框中。但cmd.exe認爲它是兩個字符,它不知道,所以它顯示? – 2013-05-11 10:47:59

+0

好的謝謝你,除了它返回了一個404,因爲你的方括號,所以更新的鏈接是http://www.joelonsoftware.com/articles/Unicode.html你的例子已經爲我打開了很多新的領土。我確實找到了有關CHARGEN服務的維基百科http://en.wikipedia.org/wiki/Barber_pole#Computer_science的參考資料。我會錯過使用默認的UTF16編碼,因爲它也使用代碼點?我看到很多語言在Utf32 – matthewbaskey 2013-05-11 14:14:36

4

使用鏈接的例子:

var largest = input.GroupBy(x => x).OrderByDescending(x => x.Count()).First(); 
var asString = new string(largest.Key, largest.Count()); 
+0

感謝這是乾淨,快速和簡潔。作爲一名Web開發人員,而不是系統程序員,對我來說,使用簡單易用的語法會更有幫助,因爲我必須跟蹤大量客戶端技術和樣式問題。我明白我現在在哪裏絆倒,實際上我有第一個陳述,但不知道如何在第二個陳述中得到結果並將其輸入到一個新的字符串中。 – matthewbaskey 2013-05-11 09:43:08

+0

我應該指定一個更具體的例子,我希望有一個很好的簡短表達式來做到這一點 – matthewbaskey 2013-05-11 15:51:11

+0

請注意,@magister想要最長的循環字符串,例如「aabbbaa」 - >「bbb」不是「aaaa」。 – 2013-05-12 22:10:01

2

沒有必要創建大量的中間物體。您只需要跟蹤最長序列中的字符和該序列的長度:

char longest = '\0'; 
int longestLength = 0; 

char last = '\0'; 
int lastLength = 0; 

foreach (char c in input) 
{ 
    if (c == last) 
    { 
     lastLength++; 

     if (lastLength > longestLength) 
     { 
      longestLength = lastLength; 
      longest = c; 
     } 
    } 
    else 
    { 
     lastLength = 1; 
    } 

    last = c; 
} 

var result = new string(longest, longestLength); 
+0

此方法不考慮字符編碼。試試這個:string input =「aabccc」; //包含理髮極點字符 – 2014-08-05 11:06:36

+1

@XavierDecoster對於最多16位的Unicode字符,此方法工作正常。例如'string input =「aab \ u2764 \ u2764 \ u22605」;'是aab❤❤❤★並且正確地導致了❤❤❤。然而,[barber極點字符](http://www.fileformat.info/info/unicode/char/1f488/index.htm)高於16位字符的閾值,因此需要代理字符對來編碼它。你可以調整這種方法在每個階段最多存儲兩個字符,並使用['Char.IsSurrogate'](http://msdn.microsoft.com/en-us/library/96xe6etk(v = vs.110))。 aspx)來檢測替代品。 – 2014-08-05 13:47:38