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

本文关键字:处理 字符串 列表 何使用 LINQ | 更新日期: 2023-09-27 18:20:34

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

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

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

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

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

有没有一种优雅的(即纯粹功能性的)方法可以做到这一点?第3步和第4步很简单,但我在第2步上遇到了麻烦,这似乎需要与SelectMany相反的东西。谢谢

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

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

当然。

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

您可以使用Linq和正则表达式:

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方法的副作用进行更新。

这里有一个使用LINQ(纯函数方式)的线性解决方案。这个想法是用#替换所有元音,然后在# 上拆分

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