我对这里已经提出的问题有一个扩展
但是,我想返回原始字符串中最长的重复字符集的列表,而不是按最高排序的 char 及其相对计数的列表。
我相当精通链接,但从未遇到过在字符串中查询 char 类型的实例,并认为有人可以给我一个提示来帮助我理解 LINQ 的特定用例......
谢谢
使用链接的示例:
var largest = input.GroupBy(x => x).OrderByDescending(x => x.Count()).First();
var asString = new string(largest.Key, largest.Count());
我假设您想要最长的子字符串。例如,对于aabccc
您想要
我还假设问题域是 Unicode 字符的字符串。不幸的是,.NETSystem.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);
}
无需创建大量中间对象。您只需要跟踪最长序列中的字符和该序列的长度:
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);