我想在.NET LINQ(C#首选)中实现以下算法:
输入是一个任意字符串。字符串的第一个字符保证是元音。例如。 "alkjihgefdcb"
将字符串分解为由元音分隔的块。例如。 "alkj"
,"ihg"
,"efdcb"
按字母顺序对每个块进行排序。例如。 "ajkl"
,"ghi"
,"bcdef"
将块连接在一起以生成输出字符串。例如。 "ajklghibcdef"
是否有一种优雅(即纯功能)的方式来做到这一点?第3步和第4步很简单,但我对第2步感到困惑,这似乎需要与SelectMany相反的东西。感谢。
编辑:我很欣赏Regex解决方案,但我正在寻找一种纯粹的基于LINQ的方法。在我的实际应用程序中,字符串是域对象列表,因此Regex不易应用。
答案 0 :(得分:2)
不确定
Regex.Split(input, @"(?=[aeiou])").Where(s => !string.IsNullOrWhiteSpace(s))
.OrderBy(n => n).Aggregate((a, b) => a + b);
如果您不想使用Regex,我们需要一个扩展方法:
public static IEnumerable<IEnumerable<T>> SplitOn<T>(this IEnumerable<T> source, params T[] splitObjs)
{
//appropriate error checking, check for null etc
if (!source.Any() || !splitObjs.Any()) return new[]{source};
List<T> buffer = new List<T>()
foreach (T item in source)
{
if (splitObjs.Contains(item) && buffer.Any())
{
yield return buffer;
buffer.Clear();
}
buffer.Add(item);
}
if (buffer.Any()) yield return buffer;
}
然后它应该如此简单:
input.SplitOn('a', 'b', 'c', 'd', 'e').Select(s => new string(s.ToArray()))
.OrderBy(n => n).Aggregate((a, b) => a + b);
答案 1 :(得分:1)
您可以使用Linq和Regular Expressions:
string.Join(
string.Empty,
Regex.Matches("alkjihgefdcb", "[aeiou][^aeiou]+")
.Cast<Match>()
.Select(m => string.Join(string.Empty, m.Value.OrderBy(c => c))));
// ajklghibcdef
或者更好:
string.Join(
string.Empty,
Regex.Split("alkjihgefdcb", "(?=[aeiou])")
.Select(m => string.Join(string.Empty, m.OrderBy(c => c))));
// ajklghibcdef
使用纯Linq:
var i = 0;
string.Join(
string.Empty,
"alkjihgefdcb".GroupBy(c => "aeiou".IndexOf(c) == -1 ? i : ++i)
.SelectMany(g => g.OrderBy(c => c)));
// ajklghibcdef
虽然我不愿意称之为真正的功能性,因为它依赖于i
方法的副作用更新GroupBy
。
答案 2 :(得分:0)
这是使用LINQ(Pure Functional方式)的一种衬垫解决方案。我们的想法是用#
替换所有元音,然后在#
string input = "alkjihgefdcb";
input = input
.Replace("a","#a")
.Replace("e","#e")
.Replace("i","#i")
.Replace("o","#u")
.Replace("u","#u")
.Split(new char[]{'#'},StringSplitOptions.RemoveEmptyEntries)
.Select (i => new string(i.ToCharArray().OrderBy (x => x).ToArray()))
.Aggregate ((a,b) => a + b);