Listedeki son öğeyi <> nasıl bulabilirim?


174

Aşağıdaki benim kod bir özü:

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;
}

Benim main () işlev kodunda aşağıdaki kullanmaya çalışıyorum:

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;
}

Sorun burada: bir for döngüsü kullanarak listemdeki tüm öğeleri yazdırmaya çalışıyorum:

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);
}

Ben benim döngü içinde cnt3 eşitlemek ve List tüm girişleri yazdırmak için son elemanı bulmak istiyorum. Listedeki her öğe, yukarıda kod örneğinde belirtildiği gibi AllIntegerIDs sınıfının bir nesnesidir. Listedeki son geçerli girişi nasıl bulurum?

İntegerList.Find (integerList []. M_MessageText == null;

Eğer bunu kullanırsam 0 ile maksimum arasında değişen bir indekse ihtiyaç duyar. Kullanmayı düşünmediğim döngü için başka bir tane kullanmak zorunda olacağım anlamına gelir. Daha kısa / daha iyi bir yol var mı?

Teşekkürler, Viren


@Viren: Kodun düzgün görünmesini sağlamak için girintili girdim. Altımda düzenlemeler yaptıysanız, bunları geri almadığımdan emin olabilir misiniz?
Sam Harwell

8
Sorunuzla ilgili değil, ancak gerekmedikçe bir finalizer uygulamamalısınız.
Brian Rasmussen

Soru ile ilgili değil, ancak okunabilirlik ve süreklilik için, bunu AllIntegerIDs newItem = new AllIntegerID();tüm alanları atamak ve sonra aramak için kullanmanızı öneririm integerList.Add(newItem). Veya alanlar yerine özellikleri ve C # 3.0 nesne başlatıcı sözdizimini kullanın.
Thorarin

Yanıtlar:


208

Listedeki son öğeye erişmek istiyorsanız,

if(integerList.Count>0)
{
   var item = integerList[integerList.Count - 1];
}

listedeki toplam öğe sayısını almak için Count özelliğini kullanabilirsiniz

var itemCount = integerList.Count;

17
@Jared Sanırım ilk satırdan önce "if (integerList.Count! = 0)" bu satırı eklemeyi unuttun
prabhakaran

21
IMHO bu en iyi cevap olmayı hak etmiyor, korkunç bir şekilde okuyor ve sayı sıfırsa hata şansı bırakıyor. CleanCode ™ yaklaşımı kullanmak olacaktır Last/ LastOrDefaultaşağıda belirtildiği gibi.
chillitom

2
Daha önce belirtildiği gibi, bu cevap liste boş olduğunda durumu dikkate almaz ve IMHO kullanılmamalıdır.
merrr

2
@chillitom @merrr LINQ uzantı yöntemlerini kullanmak yardımcı olmaz. Enumerable.Lastliste boşsa bir istisna atar. Bir Enumerable.LastOrDefaultdeğer türleri listesi arar ve iletirseniz, liste boşsa varsayılan değer döndürülür. Dolayısıyla, 0'dan bir geri List<int>alırsanız, listenin boş olup olmadığını veya son değerin 0 olduğunu bilmezsiniz. Kısacası, Counthangi karar mekanizmasını kullanmaya karar verdiğinizi kontrol etmeniz gerekir .
0b101010

4
@chillitom Her biri kendi. Bir listenin doldurulduğunu bildiğiniz durumlarda bence var element = list[list.Count - 1]çok özlü ve okunabilir. Uzatma yöntemlerini
çağırmaya

277

Bir koleksiyonun son öğesini almak için LastOrDefault () ve Last () uzantı yöntemlerini kullanın

var lastItem = integerList.LastOrDefault();

VEYA

var lastItem = integerList.Last();

Eklemeyi unutmayın using System.Linq;veya bu yöntem kullanılamaz.


18
Evet, bu en iyi yoldur, Last ve LastOrDefault <> s
chillitom

2
@Gusdor Belgelendiğini görmedim, ancak doğrudan bu şeyler için kaynaklara yöneliyorum (veya Resharper, dotPeek veya ILSpy gibi bir sökücü kullanıyorum). Ben orada görebilirsiniz itibaren First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault, ElementAtve ElementAtOrDefaultoptimize edilmiş IList<TSource>, Countve Containsiçin optimize edilmiştir ICollection<TSource>ve Cast<TResult>için optimize edilmiştir IEnumerable<TResult>.
chillitom

8
eklediğinizden emin olunusing System.Linq;
Hybrid

4
@chillitom Maruz kalınan genişletme yöntemleri System.Linq.Enumerablegerçekten 'optimize edilmemiştir'. İşte Enumerable.Lastyöntemin kodu .
0b101010

4
@chillitom kaynağını okuduktan sonra System.Linq.Enumerable.Last, ben 0b101010 katılıyorum - Last()Kod değil "için optimize List<>s" - Last()varsayılan sadece çirkin bir sarıcı olduğunu return list[list.Count-1]argüman bir olduğu durumda IListve dolaşır durumda sonuna kadar liste üzerinde eğer bu çok kötü bir çözüm yapım ... değil IListbir olduğunu LinkedListdizin sadece ben geriye yineleme geçersiz kılma bulamadı (gereksiz tüm liste üzerinden gidecek beri Item[]indeksi> Kont / 2 c # kaynaklarda, YMMV ile )

20

Sorunun kökenine bakalım, bir listenin son öğesini nasıl güvenli bir şekilde ele alalım ...

varsayarsak

List<string> myList = new List<string>();

Sonra

//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];

Listenin boş olmadığını ilk garanti etmedikçe "count-1" kötü bir alışkanlıktır.

Boş listeyi kontrol etmenin uygun bir yolu yoktur.

Düşünebildiğim en kısa yol

string myString = (myList.Count != 0) ? myList [ myList.Count-1 ] : "";

tüm dışarı çıkıp her zaman true döndüren bir temsilci yapabilir ve bunu son değeri (veya liste boşsa varsayılan oluşturulmuş valye) döndürecek olan FindLast'a geçirebilirsiniz. Bu işlev listenin sonunda başlar, bu nedenle yöntem normalde O (n) olmasına rağmen Büyük O (1) veya sabit zaman olacaktır.

//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);

Temsilci bölümünü sayarsanız FindLast yöntemi çirkindir, ancak yalnızca bir yer olarak bildirilmesi gerekir. Liste boşsa, dize için "" liste türünün varsayılan oluşturulmuş değerini döndürür. AlwaysTrue temsilcisini bir adım daha ileri götürmek, dize türü yerine bir şablon yapmak daha yararlı olacaktır.


2
Delege lambda ifadesi ile değiştirilebilir: myList.FindLast(_unused_variable_name => true);Bu türden bağımsız olarak çalışır. Daha kısa bir versiyon myList.FindLast(_ => true);, ama sadece alt çizgi (veya başka bir tek karakter tanımlayıcı) zaman zaman biraz kafa karıştırıcı olabilir buluyorum.
Bob


5

Değişiklik

for (int cnt3 = 0 ; cnt3 <= integerList.FindLastIndex ; cnt3++)

için

for (int cnt3 = 0 ; cnt3 < integerList.Count; cnt3++)

foreach genellikle daha kullanışlıdır, ancak SLIGHTLY daha yavaştır.
Eric J.

Count ... kullanıyorsanız -1 yapın veya bir dizin hatası alırsınız. için (int cnt3 = 0; cnt3 <integerList.Count - 1; cnt3 ++)
RiddlerDev

4
Bu yüzden <= 'yi <olarak değiştirdim. Kod postalandığı gibi doğru :-)
Eric J.

@Eric: Eskiden daha yavaştı, ama JIT'de vurmak önemsiz bir durum, bu yüzden şimdiye kadar yapmadılarsa şaşırırdım. : dunno:
Sam Harwell

1
@IPX Ares: Yinelemekte olduğunuz veri türüne bağlı olarak hala bir sorun gibi görünüyor: stackoverflow.com/questions/365615/…
Eric J.

3

C # 8.0'da ^ operatörün tam açıklaması ile son öğeyi alabilirsiniz

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

// Gets translated to 
var value = list[list.Count - 1];

2

CountÖzelliği kullanın . Son dizin olacak Count - 1.

for (int cnt3 = 0 ; cnt3 < integerList.Count; cnt3++)

2

İlk olarak listedeki eleman sayısını sayarak bulabilirsiniz;

int count = list.Count();

Ardından, listedeki son öğeyi almak için sayımı - 1 dizine ekleyebilirsiniz.

int lastNumber = list[count - 1];

2
Lütfen yinelenen cevaplar göndermeyin.
Ian Mercer

1

Neden yalnızca List üzerindeki Count özelliğini kullanmıyorsunuz?

for(int cnt3 = 0; cnt3 < integerList.Count; cnt3++)

0

Orijinal sorunuzdan bağımsız olarak, listenizi birden çok kez dizine eklemek yerine yerel değişkenlere referanslar yakalarsanız daha iyi performans elde edersiniz:

AllIntegerIDs ids = new AllIntegerIDs();
ids.m_MessageID = (int)IntegerIDsSubstring[IntOffset];
ids.m_MessageType = (int)IntegerIDsSubstring[IntOffset + 1];
ids.m_ClassID = (int)IntegerIDsSubstring[IntOffset + 2];
ids.m_CategoryID = (int)IntegerIDsSubstring[IntOffset + 3];
ids.m_MessageText = MessageTextSubstring;
integerList.Add(ids);

Ve fordöngünüzde:

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

-1

Önsöz gibi bir şey çok daha kolay olacağını kabul ediyorum

foreach(AllIntegerIDs allIntegerIDs in integerList)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\n", allIntegerIDs.m_MessageID,
allIntegerIDs.m_MessageType,
allIntegerIDs.m_ClassID,
allIntegerIDs.m_CategoryID,
allIntegerIDs.m_MessageText);
}

Ayrıca ben sizin gibi ekleyebilirsiniz senin .net sürümüne bağlı kamu alanlarının yerine bilgilere erişmek için özellikler eklemek öneririm public int MessageType {get; set;}ve kurtulmak m_orada should olarak vb kamu alanları, özelliklerinden.


-1

Sanırım bu sana yardımcı oluyor. lütfen kontrol edin

    TaxRangers[TaxRangers.Count]. max
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.