如何从列表中找到倒数第二个元素?

17

我有一个类似于 List<string> 的列表:

 List<String> lsRelation = new List<String>{"99","86","111","105"}.

现在我想找到数字111,它是倒数第二个字符串。

所以我尝试了:

String strSecondLast=lsrelation.Last() - 2;

这种方法不能正常工作。那么,如何使用 Last() 找到列表中倒数第二个元素呢?


如果只有一个项目或根本没有项目,应该返回什么? - Caramiriel
@Caramiriel:如果你尝试使用 arr[arr.Length],你期望数组返回什么?除了异常之外没有其他选择。在集合中,每个值都可以作为 null 的有效值。因此,你无法区分集合少于两个元素的情况和元素实际上是 null 的情况。 - Tim Schmelter
@TimSchmelter:有多种方法可以实现这一点(异常、TryGet模式、超出范围时返回null),但我只是想引导人们思考集合中可能少于两个项的可能性。 - Caramiriel
可能是查找List<T>倒数第二个元素的重复问题。 - C-Pound Guru
7个回答

21

使用:

if (lsRelation.Count >= 2)
    secLast = lsRelation[lsRelation.Count - 2];

12

C# 8.0 开始,您可以使用 Index 来获取与序列末尾相关的元素:

if (lsRelation.Count >= 2)
    secLast = lsRelation[^2];

查看文档以获取更多信息。


11

如果您知道的是具有索引器的 IList<T>

string secondLast = null;
if (lsRelation.Count >= 2)
    secondLast = lsRelation[lsRelation.Count - 2];

您可以创建一个类似于以下的扩展:

public static T SecondLast<T>(this IEnumerable<T> items)
{
    if (items == null) throw new ArgumentNullException("items");
    IList<T> list = items as IList<T>;
    if (list != null)
    {
        int count = list.Count;
        if (count > 1)
        {
            return list[count - 2];
        }
        else
            throw new ArgumentException("Sequence must contain at least two elements.", "items");
    }
    else
    {
        try
        {
            return items.Reverse().Skip(1).First();
        } catch (InvalidOperationException)
        {
            throw new ArgumentException("Sequence must contain at least two elements.", "items");
        }
    }
}

然后你可以这样使用它:

string secondLast = lsRelation.SecondLast();

在尝试使用.First()之前,可能需要检查列表是否至少包含一个项目。 - CodingIntrigue
@RGraham:为什么?这将抛出一个期望的异常。我应该返回什么?我可以返回的每个值(如default(T))都可能是有效值,这甚至比抛出有意义的异常更糟糕。 - Tim Schmelter
1
@RGraham:我已经编辑了答案,使异常更明确。 - Tim Schmelter

6
你可以使用 ElementAt(list.Count - 2)
List<String> lsRelation = new List<String> { "99", "86", "111", "105" };
Console.WriteLine(lsRelation.ElementAt(lsRelation.Count - 2)); // 111

6
有很多方法可以做到这一点。只是提及一个我还没有在这里看到的方法:
List<string> lsRelation = new List<String>{"99","86","111","105"};
String strSecondLast = lsRelation.Skip(lsRelation.Count() - 2).First();

3

使用Last()无法实现此操作,请试试以下方法:计算列表的长度并减去2:

if (lsRelation.Count >= 2)
{
    var item = lsRelation[lsRelation.Count - 2];
}

编辑:

根据评论,这里有一个使用 Last() 方法的例子,但是这种方法是不可行的:

if (lsRelation.Count >= 2)
{
    var item = lsRelation.Last(x => x == lsRelation[lsRelation.Count - 2]);
}

3
无法使用 Last() 实现这一点是不正确的,您可以使用 last 的谓词重载,并使用索引测试它是否是给定索引之前的最后一个元素... 只是用这种方式做没有意义 :) - CodingIntrigue

0

模糊的问题 - 如果您的列表只有一个元素怎么办?如果您的列表为空怎么办?如果您的列表为null怎么办?

List 的显而易见的答案是

var beforeLast = lsRelation[lsRelation.Count -2];

为了涵盖所有的边缘情况,我会使用

string beforeLast = null;
if (lsRelation != null && lsRelation.Count > 1)
   beforeLast = lsRelation[lsRelation.Count - 2];

如果它是一个 IEnumerable<string>

string beforeLast = null;
if (lsRelation != null) {
  int l_count = lsRelation.Count();
  if (l_count > 1)
     beforeLast = lsRelation.Skip(l_count - 2).Take(1);
}

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