给定排序字符串的运行长度编码
本文关键字:编码 运行 排序 字符串 | 更新日期: 2023-09-27 18:34:42
为给定字符串
的运行长度编码编写代码 示例输入:aaaabcccccc
输出: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"。
假设它是一个排序字符串。
添加一个三元表达式:
output = grp.Key + (grp.Count() > 1 ? grp.Count().ToString() : "")
尽管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,需要解释:
- 字符串
Zip
自身偏移一(Skip
(,以检测连续字符的边界 - 由于
Zip
在最短枚举处停止,因此最后一个字符在最短字符串上重复,以处理字符串中的最后一个字符。 - 与其他答案中的"排序"RLE 输入字符串不同,分组键是通过字符和"字符是否相邻吗?"音序器的组合来完成的。
- 这个序列在
GroupBy
的投影λ中的条件内相当可怕地递增 - @Jonesy/@Tim 的条件连接在
String.Join
中使用,以重新组合最终编码的字符串。
这是一个简化版本:
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
循环和字符串生成器的混乱。
您可以使用条件运算符来处理核心问题。另一种方法是使用类似于字典的Lookup
和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())));
请检查
下面的代码,它可能会有所帮助:
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();
我刚刚发现了一个简短的正则表达式解决方案。在这里发布分享,以及一个很棒的正则表达式备忘单。
Regex.Replace(input, @"('D)'1+", c => c.Length.ToString() + c.Value[0]);