如何找到List <>中的最后一个元素?

zac*_*ack 154 c# for-loop list

以下是我的代码摘录:

public class AllIntegerIDs 
{
    public AllIntegerIDs() 
    {            
        m_MessageID = 0;
        m_MessageType = 0;
        m_ClassID = 0;
        m_CategoryID = 0;
        m_MessageText = null;
    }

    ~AllIntegerIDs()
    {
    }

    public void SetIntegerValues (int messageID, int messagetype,
        int classID, int categoryID)
    {
        this.m_MessageID = messageID;
        this.m_MessageType = messagetype;
        this.m_ClassID = classID;
        this.m_CategoryID = categoryID;
    }

    public string m_MessageText;
    public int m_MessageID;
    public int m_MessageType;
    public int m_ClassID;
    public int m_CategoryID;
}
Run Code Online (Sandbox Code Playgroud)

我试图在我的main()函数代码中使用以下内容:

List<AllIntegerIDs> integerList = new List<AllIntegerIDs>();

/* some code here that is ised for following assignments*/
{
   integerList.Add(new AllIntegerIDs());
   index++;
   integerList[index].m_MessageID = (int)IntegerIDsSubstring[IntOffset];
   integerList[index].m_MessageType = (int)IntegerIDsSubstring[IntOffset + 1];
   integerList[index].m_ClassID = (int)IntegerIDsSubstring[IntOffset + 2];
   integerList[index].m_CategoryID = (int)IntegerIDsSubstring[IntOffset + 3];
   integerList[index].m_MessageText = MessageTextSubstring;
}
Run Code Online (Sandbox Code Playgroud)

问题在这里:我试图使用for循环打印列表中的所有元素:

for (int cnt3 = 0 ; cnt3 <= integerList.FindLastIndex ; cnt3++) //<----PROBLEM HERE
{
   Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\n", integerList[cnt3].m_MessageID,integerList[cnt3].m_MessageType,integerList[cnt3].m_ClassID,integerList[cnt3].m_CategoryID, integerList[cnt3].m_MessageText);
}
Run Code Online (Sandbox Code Playgroud)

我想找到最后一个元素,以便在我的for循环中将cnt3等同并打印出List中的所有条目.列表中的每个元素都是AllIntegerIDs类的对象,如上面代码示例中所述.如何在列表中找到最后一个有效条目?

我应该使用像integerList.Find(integerList [] .m_MessageText == null;

如果我使用它,它将需要一个范围从0到任何最大值的索引.意味着我将不得不使用另一个for循环,我不打算使用它.有更短/更好的方式吗?

谢谢,Viren

Kun*_*han 248

要获取集合的最后一项,请使用LastOrDefault()Last()扩展方法

var lastItem = integerList.LastOrDefault();
Run Code Online (Sandbox Code Playgroud)

要么

var lastItem = integerList.Last();
Run Code Online (Sandbox Code Playgroud)

记得要添加using System.Linq;,否则此方法将无法使用.

  • 这是最好的方法,Last和LastOrDefault针对List <>进行了优化 (14认同)
  • 确保添加`using System.Linq;` (8认同)
  • @chillitom`System.Linq.Enumerable`公开的扩展方法并没有真正"优化".这是"Enumerable.Last"方法的代码. (4认同)
  • @chillitom在阅读了`System.Linq.Enumerable.Last`的源代码后,我同意0b101010 - `Last()`代码**不是**"优化为`List <>`s - "Last( )`只是一个丑陋的包装器,默认为`return list [list.Count-1]`,如果参数是`IList`,**在列表上迭代**直到结束,以防它不是..如果`IList`是一个`LinkedList`,那么它将成为一个非常糟糕的解决方案,因为索引器将不必要地遍历整个列表(我还没有找到一个覆盖迭代迭代`Item []`,索引> Count/2#在c#来源中,YMMV) (4认同)
  • @Gusdor我没有看到它的文档,但我倾向于直接针对这些东西使用源文件(或使用诸如Resharper,dotPeek或ILSpy之类的反汇编程序)。从那里我可以看到,对Firstist,FirstOrDefault,Last,LastOrDefault,Single,SingleOrDefault,ElementAt和ElementAtOrDefault的优化是针对IList &lt;TSource&gt;,Count进行的。和`Contains`针对ICollection &lt;TSource&gt;优化,而Cast &lt;TResult&gt;针对IEnumerable &lt;TResult&gt;优化。 (2认同)
  • http://www.dotnetframework.org/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/src/Core/System/Linq/Enumerable@cs/1407647/枚举@ CS (2认同)
  • @vaxquis - 澄清一下,它*针对“List &lt;&gt;”进行了优化。具体来说,是“IList”的所有后代。不过,正如您所说,遗憾的是它没有针对“LinkedList&lt;&gt;”进行优化。 (2认同)

Jar*_*red 185

如果您只想访问列表中的最后一项,则可以执行此操作

var item = integerList[integerList.Count - 1];
Run Code Online (Sandbox Code Playgroud)

要获取列表中的项目总数,您可以使用Count propery

var itemCount = integerList.Count;
Run Code Online (Sandbox Code Playgroud)

  • 恕我直言,这不应该是最好的答案,它读得非常糟糕,如果计数为零,就有机会出错._CleanCode™_方法将使用如下所述的"Last"/"LastOrDefault". (18认同)
  • @Jared我想你忘了在第一行之前添加这行"if(integerList.Count!= 0)" (16认同)
  • @chillitom各自给自己.在您知道列表已填充的情况下,我认为`var element = list [list.Count - 1]`非常简洁且可读.无需调用扩展方法 (3认同)
  • 如前所述,这个答案没有考虑到列表为空时的情况,不应该使用恕我直言. (2认同)
  • @chillitom @merrr 使用 LINQ 扩展方法没有帮助。如果列表为空,`Enumerable.Last` 将抛出异常。如果您调用 Enumerable.LastOrDefault 并传递值类型列表,则如果列表为空,则将返回默认值。因此,如果您从 `List&lt;int&gt;` 返回 0,您将不知道列表是空的还是最后一个值是 0。简而言之,无论您决定使用哪种检索机制,您都需要检查 `Count`。 (2认同)

小智 27

在 C# 8.0 中,您可以使用 ^ 运算符获取最后一项完整说明

List<char> list = ...;
var value = list[^1]; 

// Gets translated to 
var value = list[list.Count - 1];
Run Code Online (Sandbox Code Playgroud)


小智 16

让我们来看问题的根源,如何安全地解决List的最后一个元素......

假设

List<string> myList = new List<string>();
Run Code Online (Sandbox Code Playgroud)

然后

//NOT safe on an empty list!
string myString = myList[myList.Count -1];

//equivalent to the above line when Count is 0, bad index
string otherString = myList[-1];
Run Code Online (Sandbox Code Playgroud)

"count-1"是一个坏习惯,除非你首先保证列表不为空.

除了这样做之外,没有一种方便的方法来检查空列表.

我能想到的最短路是

string myString = (myList.Count != 0) ? myList [ myList.Count-1 ] : "";
Run Code Online (Sandbox Code Playgroud)

你可以全力以赴,创建一个总是返回true的委托,并将它传递给FindLast,它将返回最后一个值(如果列表为空,则返回默认构造的valye).该函数从列表的末尾开始,因此将是Big O(1)或常数时间,尽管该方法通常为O(n).

//somewhere in your codebase, a strange delegate is defined
private static bool alwaysTrue(string in)
{
    return true;
}

//Wherever you are working with the list
string myString = myList.FindLast(alwaysTrue);
Run Code Online (Sandbox Code Playgroud)

如果计算委托部分,FindLast方法很难看,但只需将其声明为一个地方.如果列表为空,它将为字符串返回列表类型""的默认构造值.将alwaysTrue委托更进一步,使其成为模板而不是字符串类型,将更有用.

  • 可以用lambda表达式替换该委托:`myList.FindLast(_unused_variable_name =&gt; true);`不管类型如何,该函数都可以工作。较短的版本是`myList.FindLast(_ =&gt; true);`,但我发现下划线(或任何其他单个字符标识符)有时会有些混乱。 (2认同)

Dan*_*plo 8

int lastInt = integerList[integerList.Count-1];
Run Code Online (Sandbox Code Playgroud)


小智 8

虽然这是 11 年前发布的,但我确信正确的答案数量比实际数量还多一个!

你也可以做类似的事情;


if (integerList.Count > 0) 
   var item = integerList[^1];

Run Code Online (Sandbox Code Playgroud)

请参阅几个月前关于 MS C# 文档的教程文章。

我个人仍然会坚持LastOrDefault()/Last()但我想我会分享这一点。

编辑; 刚刚意识到另一个答案已经通过另一个文档链接提到了这一点。


Eri*_* J. 5

改变

for (int cnt3 = 0 ; cnt3 <= integerList.FindLastIndex ; cnt3++)
Run Code Online (Sandbox Code Playgroud)

for (int cnt3 = 0 ; cnt3 < integerList.Count; cnt3++)
Run Code Online (Sandbox Code Playgroud)

  • 这就是为什么我将 &lt;= 更改为 &lt;。代码是正确的:-) (4认同)