2012-01-04 100 views
20

所以我有一个字符串列表,看起来像这样:的LINQ:如何获得倒数第二

var ls=new List<string>() 
    { 
     "100", 
     "101-102-1002", 
     "105-153-1532-1532", 
     "105-1854-45-198", 
     "180-95-45-200" 
    }; 

我想要得到的断续线的倒数第二个。所以,我的输出是这样的:

null, 
102, 
1532, 
45, 
45 

我有这方面的解决方案,它看起来像这样:

ls.Select (l =>l.Split('-').Select ((s,i) =>new {s,i}) 
.OrderByDescending (x=>x.i).Skip(1).Take(1)) 

我认为这种解决方案可能是复杂,这个简单的任务。所以我的问题是:你们有没有更简单的解决方案来解决这个问题?

+2

分机的结果是错误的或者我不明白的问题:应该不会吧be:null,102,153,1235? – 2012-01-04 08:55:36

+1

您的解决方案对我来说看起来很好! – ColinE 2012-01-04 08:55:46

+0

是的,它应该是拆分字符串的第二个最后一个。如果没有倒数第二个,那么它应该返回null。 – Arion 2012-01-04 09:00:25

回答

31

Reverse非常适合在这里:

ls.SelectMany(l =>l.Split('-').Reverse().Skip(1).Take(1).DefaultIfEmpty()) 

我也用SelectMany改造IEnumerable<IEnumerable<string>><IEnumerable<string>

+1

这种解决方案的唯一的问题是你不会得到“空”时splited阵列长度小于2 这是接近但不正确的,因为这吐出空白而不是“空” ls.Select(X => X 。.Split( ' - ')反向()跳过(1)。取(1).FirstOrDefault())ToList(); – Anand 2012-01-04 09:14:19

+0

@Anand是的,谢谢你的提示。不过,我更喜欢我的LINQ代码留在LINQ monad中。 – 2012-01-04 09:20:46

+0

@TimSchmelter我不明白你的意思。如果'ls'为空,则结果将为空。如果'ls'中的项太短而且没有至少两个组件,则结果将包含'null'来代替该项。这种行为可能看起来很奇怪,但这是作者想要的,不是吗? – 2014-04-24 05:43:49

2
var ls = new List<string> { "100", "101-102-1002", "105-153-1532-1532", "12-1235-785" }; 
var result = ls.Select(x => 
{ 
    var tokens = x.Split('-'); 
    if (tokens.Length < 2) 
    { 
     return null; 
    } 
    return tokens[tokens.Length - 2]; 
}); 
12
 var ls = new List<string>() { "100", "101-102-1002", "105-153-1532-1532", "12-1235-785" }; 
     var result = from p in ls 
        let arr = p.Split('-') 
        select arr.Length < 2 ? null : arr[arr.Length - 2]; 

     foreach (var item in result) 
     { 
      Console.WriteLine(item); 
     } 



     Console.Read(); 
+0

这应该是答案。它比另一个更快。 – DanielCuadra 2014-04-09 16:34:31

6
var ls = new List<string>(){"100","101-102-1002","105-153-1532-1532","12-1235-785"}; 

var result = from l in ls 
      let s = l.Split('-') 
      select s.ElementAtOrDefault(s.Length - 2); 
+0

长度小于2时不吐出'空',而是FirstOrDefault吐出空白。 – Anand 2012-01-04 09:16:13

+0

@Anand,不确定你的意思,它确实为第一个条目返回'null'。 – 2012-01-04 09:27:10

6

如果你有

var ls = new List<string>(...);

然后

var result = ls.Reverse().Skip(1).Take(1);

应该工作。

0

在lambda语法:

var ls = new List<string>() { "100", "101-102-1002", "105-153-1532-1532", "12-1235-785" }; 

var result = ls.Select(x => new { split = x.Split('-') }).Select(y => y.split.LastOrDefault(z => z != y.split.LastOrDefault())); 
+0

所以,你知道,如果你突出显示你的文本并点击“代码”按钮,它将正确格式化为代码块显示给你。这次我已经提交并提交并编辑了它。 – Amicable 2014-04-09 16:29:08

1

我已经创建了一个基于帕维尔·加季洛夫的回答以上

public static TSource SecondLast<TSource>(this IEnumerable<TSource> source) 
{ 
      //from http://stackoverflow.com/questions/8724179/linq-how-to-get-second-last 
      return source.Reverse().Skip(1).Take(1).FirstOrDefault(); 
}