使用Linq将字符串拆分为List<string>

12

我希望避免循环。

我有这个:

string s = "AAAA,12,BBBB,34,CCCCC,56";

使用Linq,我想要有两个列表

第一个列表包括: AAAA,BBBB和CCCCC

第二个列表包括:12、34和56

不基于数字或非数字。

谢谢,


这里有一个不错的教程:http://msdn.microsoft.com/en-us/library/bb397915.aspx - Jeff Norman
1
字符串的分区是基于什么的?列表中的位置、字符数等吗? - Dave M
是的,它在列表中的位置。 - TheBoubou
2
我想避免循环。你应该意识到,无论你决定使用哪种LINQ解决方案,它实际上都会使用至少一个循环。 - Winston Smith
@温斯顿·史密斯:Linq解决方案可以使用递归函数调用而不是循环。但我猜克里斯的观点可能是他正在寻找一种声明性解决方案,而不是命令式的解决方案。(即使它最终被编译为命令式汇编代码。) - Niki
8个回答

32

你可以使用

var str = "AAAA,12,BBBB,34,CCCCC,56";

var spl = str.Split(',');
var l1 = spl.Where((x, y) => y % 2 == 0).ToList();
var l2 = spl.Where((x, y) => y % 2 == 1).ToList();

这将检查索引是否为偶数或奇数。


10

让我们使用Aggregate来玩一下(同时也证明这可以作为一个单一的表达式完成):

"AAAA,12,BBBB,34,CCCC,56".Split(',').Aggregate(
    new { Uneven = new List<string>(), Even = new List<string>() },
    (seed, s) => { 
        if (seed.Uneven.Count > seed.Even.Count) 
            seed.Even.Add(s);
        else
            seed.Uneven.Add(s);
        return seed;
    });

根据LINQPad,结果如下所示: alt text

当然,我可能不会这样做,因为它很难阅读。而且测试哪个列表要添加到,嗯,不太好。

但至少我们现在有了另一个lambda语句的例子 - 通常LINQ的文献会试图忘记它们(可能是因为它们不能与使用表达式树的SQL或任何其他后端一起工作)。

与上面更干净的解决方案相比,此方法的优点是只对列表进行一次遍历。但由于我们正在拆分字符串,因此我会尝试在其他地方进行优化;) 一个IEnumerable<string> Split(this string self, string boundary)会很酷吧?


如果累加器函数修改源参数,那么这似乎是对“Aggregate”的奇怪滥用。这感觉像是遵循函数式编程的字面意义,却违背了其精神。我是唯一一个这样认为的吗? - Niki
@nikie,您所说的“source parameter”是指TSource(未修改)还是TAccumulate(已修改,但这不总是这种情况吗?)? - Daren Thomas
@gaearon,是的,这并不是真实世界中的情况,除非您想要对对象列表的属性进行加权平均。然后像这样使用Aggregate就可以发挥作用(特别是因为您可以添加第三个参数以返回/格式化最终结果)。 - Daren Thomas
我是说,当然是TAccumulate。我认为它不应被修改。例如,如果我使用Aggregate计算一组数字的和或积,则聚合函数应该只返回其参数的乘积或总和,而不改变其中任何一个数。在这种情况下,“函数式”解决方案(例如,如果您使用Haskell或* ML编写它)可能会在链接列表上工作,并创建一个具有廉价的“Cons”指令的新链接列表,而不是修改其参数。 (在我看来,Linq应该包括一种链接列表类型,可以让您做到这一点。) - Niki

6

假设规则是将一个列表中的每个第二个字符串放入一个列表中,其他字符串放入另一个列表中,则可以按照以下方式操作:

        string s = "AAAA,12,BBBB,34,CCCCC,56";

        var parts = s.Split(',');

        var first = parts.Where((p, i) => i % 2 == 0);
        var second = parts.Where((p, i) => i % 2 == 1);

2

我不确定你的最终目标是什么,但你可以尝试这样做:

var strings = s.Split(',').Where( (s,p) => p % 2 == 0)

1

这里是针对那些感兴趣的人的isnumeric和not numeric过滤器...我意识到它并不是必需的

 string x =  "AAAA,12,BBBB,34,CCCCC,56";

Regex  _isNumber = new Regex(@"^\d+$");

string[] y = x.Split(',') .Where(a => _isNumber.IsMatch(a)).ToArray();
string[] z  =x.Split(',') .Where(a => !_isNumber.IsMatch(a)).ToArray();

1
你可以按位置进行分组,并从组中提取列表,像这样:
        public IEnumerable<IEnumerable<T>> ToLists<T>(IEnumerable<T> sequence)
        {
            var res = sequence.Select((item, position) => new { Item = item, Position = position })
                              .GroupBy(pair => pair.Position % 2 == 0,pair => pair.Item);
            return from grouping in res
                   select grouping;
        }

如果您希望列表是不同类型的,可以遍历结果。这就是为什么返回类型不是IEnumerable>而是IEnumerable>。使用ToList将迭代序列,但如果您想对每个元素执行某些操作,那么最好合并这些操作,使一次迭代通过序列变得多余。

0

非常有趣,没有副作用和无需方法调用。

"TesteDessaBudega".Aggregate(new List<List<char>>(), 
(l, c) => char.IsUpper(c) ? 
    l.Union(
        new List<List<char>>(){
            new List<char>(){c}
        }
    ).ToList() : 
    l.Take(l.Count - 1).Union(
        new List<List<char>>(){
            l.Last().Union(
                new List<char>(){c}
            ).ToList()
        }
    ).ToList() 
)

哦,只是为了更有趣在VB.NET上。

"TesteDessaBudega".Aggregate(New List(Of List(Of Char))(), 
Function(l, c) If(Char.IsUpper(c),
    l.Union(
        New List(Of List(Of Char))(New List(Of Char)(){
            New List(Of Char)(New Char(){c})
        })
    ).ToList(),
    l.Take(l.Count - 1).Union(
        New List(Of List(Of Char))(New List(Of Char)(){
            l.Last().Union(
                New List(Of Char)(New Char(){c})
            ).ToList()
        })
    ).ToList() 
))

linqresult


1
真的不确定这与问题有任何关系。我有一种感觉你在回答另一个问题。 - btlog

-1
如果列表未排序,每个第二项为数字,则可以像这样处理
var stringList = "AAAA,12,BBBB,34,CCCCC,56".Split(',');

var intsAsStrings = stringList.Where(
        (x) =>
        {
            int i;
            return int.TryParse(x, out i);
        }).ToList();

var strings = stringList.Where(x => !intsAsStrings.Contains(x)).ToList();

为什么不直接使用Except而不是Where(x => !intsAsStrings.Contains(x))?此外,这也不是问题作者想要的。 - sloth
不知道Except方法,不错。 - Xorandor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接