5

为给定字符串的运行长度编码编写代码
示例输入:aaaaaaaaabcccccc
输出:a10bc6

我的代码:

static void Main(string[] args)
{
    string str = "aaaaaaaaaabcccccc";
    var qry = (from c in str
               group c by c into grp
               select new
               {
                   output = grp.Key.ToString() + grp.Count().ToString()
               });
    StringBuilder sb = new StringBuilder();
    foreach (var item in qry)
    {
        sb.Append(item.output);
    }
    Console.WriteLine(sb.ToString());
    Console.ReadLine();
}

但是它返回:

a10b1c6

我想删除非重复字符的计数,这里是字母“b”的“1”。

假设它是一个排序的字符串。

4

6 回答 6

4

添加三元表达式:

output = grp.Key + (grp.Count() > 1 ? grp.Count().ToString() : "")
于 2014-12-19T20:37:02.547 回答
3

尽管 OP 事后确实提到,在他/她的情况下,他的源字符串已排序,但通常,运行长度编码的输入不会被排序,因为会丢失信息并且无法解压缩。这是对未排序的更一般情况的看法:

  string str = "aaaaaaaabccccccaadddddaaa"; // a8bc6a2d5a3

  // Zip the string with itself, offset by 1 character. 
  // Duplicate the last char to make strings equal length
  var pairs = str
    .Zip((str + str.Last()).Skip(1),
         (prev, current) => new { prev, current });

  // Retain a horrid mutable sequence which tracks consecutive characters
  var sequence = 0;
  var grps = pairs.GroupBy(p => 
    new { Ch = p.prev, 
          Sequence = p.current == p.prev
          ? sequence 
          : sequence++});

  // Join this together, using the other solutions to drop the count from single chars
  var rle = String.Join("", 
    grps.Select(g => g.Count() > 1
        ? g.Key.Ch.ToString() + g.Count().ToString() 
        : g.Key.Ch.ToString()));
  Console.WriteLine(rle);

编辑
我猜数字评论表明违反了需要解释的POLA :

  • 字符串被Zipped 自身偏移一 ( Skip),以便检测连续字符的边界
  • 由于Zip在最短的枚举上停止,最后一个字符在最短的字符串上重复以处理字符串中的最后一个字符。
  • 与其他答案中的“排序”RLE 输入字符串不同,分组键是由字符和“字符是否相邻?”的组合完成的。音序器。
  • 这个序列在GroupBy
  • @Jonesy's / @Tim's 条件连接在 aString.Join中用于重新组装最终的编码字符串。
于 2014-12-19T21:42:06.807 回答
1

您可以将条件运算符用于核心问题。另一种方法是使用Lookup类似于字典的 a 和String.Concat

var charLook = input.ToLookup(c => c);
string result = string.Concat(charLook
    .Select(g => string.Format("{0}{1}", g.Key, g.Count()==1 ? "" : g.Count().ToString())));
于 2014-12-19T20:43:49.303 回答
1

这是一个简化版本:

public static void Main()
{
   string str = "aaaaaaaaaabcccccc";
    var qry = (from c in str
               group c by c into grp
               let c = grp.Count()
               select grp.Key.ToString() + (c > 1 ? c.ToString() : ""));

    Console.WriteLine(string.Join("",qry));
    Console.ReadLine();
}

您需要注意三元表达式周围的括号放置,然后我曾经string.Join避免使用for each循环和字符串构建器。

于 2014-12-19T20:44:55.707 回答
0

请检查下面的代码,它可能会有所帮助:

StringBuilder sb = new StringBuilder();
string x = "aaaaaaaaaabcccccc";
char[] c = x.ToCharArray();
char[] t = c.Distinct().ToArray();
for (int i = 0; i < t.Length; i++)
{
   int count = 0;

   for (int j = 1; j < c.Length; j++)
   {  
       if (t[i] == c[j - 1])
       {
          count++;
       }
   }

   if (count > 1)
   {
       sb.Append(t[i] + count.ToString());
   }
   else
   {
       sb.Append(t[i]);
   }

}
Console.Write(sb);
Console.ReadKey();
于 2018-03-01T17:37:05.077 回答
0

我刚刚发现了一个简短的 RegEx 解决方案。在这里发布以分享,以及一个很棒的 RegEx 备忘单

Regex.Replace(input, @"(\D)\1+", c => c.Length.ToString() + c.Value[0]);
于 2021-11-10T18:10:47.773 回答