【问题标题】:Splitting string into words length-based lists c#将字符串拆分为基于单词长度的列表c#
【发布时间】:2012-07-07 20:45:32
【问题描述】:

我有一串用空格分隔的单词。如何根据单词长度将字符串拆分成单词列表?

示例

输入:

" aa aaa aaaa bb bbb bbbb cc ccc cccc cccc bbb bb aa "

输出:

List 1 = { aa, bb, cc}
List 2 = { aaa, bbb, ccc}
List 3 = { aaaa, bbbb, cccc}

【问题讨论】:

    标签: c# string list


    【解决方案1】:

    您可以使用Where 来查找与谓词匹配的元素(在这种情况下,具有正确的长度):

    string[] words = input.Split();
    
    List<string> twos = words.Where(s => s.Length == 2).ToList();
    List<string> threes = words.Where(s => s.Length == 3).ToList();
    List<string> fours = words.Where(s => s.Length == 4).ToList();
    

    您也可以使用GroupBy 一次查找所有组:

    var groups = words.GroupBy(s => s.Length);
    

    您也可以使用ToLookup,这样您就可以轻松索引以查找特定长度的所有单词:

    var lookup = words.ToLookup(s => s.Length);
    foreach (var word in lookup[3])
    {
        Console.WriteLine(word);
    }
    

    结果:

    啊啊啊 bbb ccc

    在线查看:ideone


    在您的更新中,您似乎想要删除空字符串和重复的单词。前者可以使用StringSplitOptions.RemoveEmptyEntries,后者可以使用Distinct

    var words = input.Split((char[])null, StringSplitOptions.RemoveEmptyEntries)
                     .Distinct();
    var lookup = words.ToLookup(s => s.Length);
    

    输出:

    aa, bb, cc
    aaa, bbb, ccc
    aaaa, bbbb, cccc
    

    在线查看:ideone

    【讨论】:

    • 第一个变体将迭代words 三次。对于一个小的input,这可能无关紧要。
    • @Mark你知道有没有类似ideone的with代码补全?或者ideone是否支持它,我只是没有找到它?
    【解决方案2】:

    首先,让我们声明一个可以保存长度和单词列表的类

    public class WordList
    {
        public int WordLength { get; set; }
        public List<string> Words { get; set; }
    }
    

    现在,我们可以用

    构建一个单词列表列表
    string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
    string[] words = input.Trim().Split();
    List<WordList> list = words
        .GroupBy(w => w.Length)
        .OrderBy(group => group.Key)
        .Select(group => new WordList { 
            WordLength = group.Key, 
            Words = group.Distinct().OrderBy(s => s).ToList() 
        })
        .ToList();
    

    列表分别按长度和字母顺序排序。


    结果

    例如

    list[2].WordLength ==> 4
    list[2].Words[1] ==> "bbbb"
    

    更新

    如果需要,您可以立即处理结果,而不是将其放入数据结构中

    string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
    
    var query = input
        .Trim()
        .Split()
        .GroupBy(w => w.Length)
        .OrderBy(group => group.Key);
    
    // Process the result here
    foreach (var group in query) {
        // group.Key ==> length of words
        foreach (string word in group.Distinct().OrderBy(w => w)) {
           ...
        }
    }
    

    【讨论】:

    • 我插入了调试器 Locals 窗口的屏幕截图。
    • 没有字符串 [] 可以吗?我的意思是 input.split 直接。
    • 是的,将words.GroupBy(... 替换为input.Trim().Split().GroupBy(...
    • @Olivier,对于输出的合适数据结构而不是使用 list 有什么建议吗?因为在那之后,我会将每个列表写入 excel 列。谢谢
    • 如果您不需要将结果存储在某种数据结构中,我更新了我的答案以展示一种简单的方法。注意:LINQ 查询不存储结果,而是在动态循环时生成结果。事实上,查询甚至没有在var query = input ... 中执行。
    【解决方案3】:

    你可以使用 Linq GroupBy

    编辑 现在我应用了 Linq 来生成你想要输出的字符串列表。

    edit2 应用多个输入,单个输出,如已编辑的问题。这只是 Linq 中的一个 Distinct 调用

    string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
    
    var list = input.Split(' ');
    
    var grouped = list.GroupBy(s => s.Length);
    
    foreach (var elem in grouped)
    {
        string header = "List " + elem.Key + ": ";
        // var line = elem.Aggregate((workingSentence, next) => next + ", " + workingSentence);
    
        // if you want single items, use this
        var line = elem.Distinct().Aggregate((workingSentence, next) => next + ", " + workingSentence);
        string full = header + " " + line;
        Console.WriteLine(full);
    }
    
    
    // output: please note the last blank in the input string! this generates the 0 list
    List 0:  ,
    List 2:  cc, bb, aa
    List 3:  ccc, bbb, aaa
    List 4:  cccc, bbbb, aaaa
    

    【讨论】:

    • @ Mare,您的代码会列出单词还是仅列出长度?请问,它与原始帖子的输出匹配吗?
    • 在这个例子中,它将输出长度,然后是单词,每一个都在一行中。
    • @ Mare, GREAT .... 但我想将每个长度的单词放在一个列表中,或者对输出的合适数据结构有什么建议吗?使用锯齿状数组好吗?
    • 已编辑示例以满足您的需求。如果你给我一个锯齿状数组的例子,我会为你构建一个适合它的 Linq。注意:Linq 从 GroupBy 提供一个 GroupedEnumerable。这包含一个键,在这种情况下是长度和组中的元素。
    • @ Mare,对于输出的合适数据结构而不是使用 list 有什么建议吗?因为在那之后,我会将每个列表写入 excel 列。谢谢
    【解决方案4】:

    编辑:我很高兴我的原始答案帮助 OP 解决了他们的问题。然而,在稍微思考了这个问题之后,我已经适应了它(我强烈建议反对我以前的解决方案,我已经在帖子末尾留下了)。

    一种简单的方法

    string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc cccc bbb bb aa ";
    var words = input.Trim().Split().Distinct();
    var lookup = words.ToLookup(word => word.Length);
    

    说明

    首先,我们修剪输入以避免来自外部空间的空元素。然后,我们将字符串拆分为一个数组。如果单词之间有多个空格,您需要像Mark's answer 一样使用StringSplitOptions

    在调用Distinct 使每个单词只包含一次之后,我们现在将wordsIEnumerable&lt;string&gt; 转换为Lookup&lt;int, string&gt;,其中单词的长度由键(int) 表示,单词本身存储在值(string)

    等等,这怎么可能?我们不是每个键都有多个单词吗?当然,但这正是 Lookup 类的用途:

    Lookup&lt;TKey, TElement&gt; 表示一组键,每个键映射到一个或多个 价值观。 Lookup&lt;TKey, TElement&gt; 类似于 Dictionary&lt;TKey, TValue&gt;。不同之处在于 Dictionary 将键映射到单个值,而 Lookup 将键映射到值集合

    您可以通过在对象上调用ToLookup 来创建Lookup 的实例 实现IEnumerable&lt;T&gt;


    注意
    没有公共构造函数来创建 Lookup 的新实例。 此外,查找对象是不可变的,也就是说,您不能添加或 在创建后从查找中删除元素或键。

    word =&gt; word.LengthKeySelector lambda:它定义了我们要按单词的长度索引(或分组,如果你愿意的话)Lookup

    用法

    将所有单词写入控制台

    (类似于问题最初要求的输出)

    foreach (var grouping in lookup)
    {
        Console.WriteLine("{0}: {1}", grouping.Key, string.Join(", ", grouping));
    }
    

    输出

    2: aa, bb, cc
    3: aaa, bbb, ccc
    4: aaaa, bbbb, cccc
    

    将所有一定长度的单词放在List

    List<String> list3 = lookup[3].ToList();
    

    按键排序

    (请注意,这些将返回IOrderedEnumerable&lt;T&gt;,因此不再可以通过密钥访问)

    var orderedAscending = lookup.OrderBy(grouping => grouping.Key);
    var orderedDescending = lookup.OrderByDescending(grouping => grouping.Key);
    

    原始答案 - 请不要这样做(性能不佳,代码混乱):

    string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc cccc bbb bb aa ";
    Dictionary<int, string[]> results = new Dictionary<int, string[]>();
    var grouped = input.Trim().Split().Distinct().GroupBy(s => s.Length)
        .OrderBy(g => g.Key); // or: OrderByDescending(g => g.Key);
    foreach (var grouping in grouped)
    {
        results.Add(grouping.Key, grouping.ToArray());
    }
    

    【讨论】:

    • 我认为我们需要先按计数对单词进行分组,这样我们才能减少数量或单词。然后我们可以根据它们的长度将它们分成数组列表。我说的对吗?
    • @Qaesar words.Distinct().GroupBy(s =&gt; s.Length); 正在为我工​​作。它不是给你预期的结果吗?
    • 我可以不使用 string[] words = input.Split(); ??我的意思是直接吐出字符串?
    • 很好,但是为什么每个长度的单词都用逗号分隔。我希望每个单词都是数组或列表的一个元素。所以我们可以使用数组数组或列表列表。这样更好吗?
    • @Qaesar 当然;)看看我编辑的答案。如果这还不够,这可能表明您需要编辑您的问题并更具体地说明您要完成的工作。
    【解决方案5】:

    有点冗长的解决方案,但确实会在字典中得到结果

    class Program
        {
            public static void Main()
            {
                Print();
                Console.ReadKey();
            }
    
            private static void Print()
            {
                GetListOfWordsByLength();
    
                foreach (var list in WordSortedDictionary)
                {
                    list.Value.ForEach(i => { Console.Write(i + ","); });
                    Console.WriteLine();
                }
            }
    
            private static void GetListOfWordsByLength()
            {
                string input = " aa aaa aaaa bb bbb bbbb cc ccc cccc ";
    
                string[] inputSplitted = input.Split(' ');
    
                inputSplitted.ToList().ForEach(AddToList);
            }
    
            static readonly SortedDictionary<int, List<string>> WordSortedDictionary = new SortedDictionary<int, List<string>>();
    
            private static void AddToList(string s)
            {
                if (s.Length > 0)
                {
                    if (WordSortedDictionary.ContainsKey(s.Length))
                    {
                        List<string> list = WordSortedDictionary[s.Length];
                        list.Add(s);
                    }
                    else
                    {
                        WordSortedDictionary.Add(s.Length, new List<string> {s});
                    }
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-22
      • 1970-01-01
      • 2014-07-31
      • 1970-01-01
      • 2018-04-06
      • 2011-11-03
      • 2017-08-16
      • 2018-03-13
      相关资源
      最近更新 更多