如何使用LINQ按元音处理字符串列表?

时间:2013-07-01 22:56:18

标签: c# linq functional-programming

我想在.NET LINQ(C#首选)中实现以下算法:

  1. 输入是一个任意字符串。字符串的第一个字符保证是元音。例如。 "alkjihgefdcb"

  2. 将字符串分解为由元音分隔的块。例如。 "alkj""ihg""efdcb"

  3. 按字母顺序对每个块进行排序。例如。 "ajkl""ghi""bcdef"

  4. 将块连接在一起以生成输出字符串。例如。 "ajklghibcdef"

  5. 是否有一种优雅(即纯功能)的方式来做到这一点?第3步和第4步很简单,但我对第2步感到困惑,这似乎需要与SelectMany相反的东西。感谢。

    编辑:我很欣赏Regex解决方案,但我正在寻找一种纯粹的基于LINQ的方法。在我的实际应用程序中,字符串是域对象列表,因此Regex不易应用。

3 个答案:

答案 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);