.NET Tip #12: Generické kolekce (1/6) - List

Tomáš Jecha, MVP, MCSD       11.10.2008       C#, VB.NET, .NET Tips       16821 zobrazení

Generická třída znamená, že při jejím použití krom jejího jména uvádíme i tzv. generické parametry, což jsou datové typy, se kterými bude generická třída pracovat. V prvním ze sedmi příspěvků o generických kolekcích vestavěných v .NET Frameworku si probereme seznam System.Collections.Generic.List<T>. Předáváme mu jeden generický pametr (písmeno T ve špičatých závorkách), což je určení datového typu, kterým můžeme seznam plnit.

List funguje jako běžná kolekce, do které můžeme vkládat položky, mazat a odkazovat se do něj jako do pole běžným číselným indexem. Jedná se o jednu z nejužitečnějších tříd v .NET Frameworku. V příkladu si nadefinujeme seznam s generickým typem String (tedy na vkládání řetězců) a ukážeme si několik z řady funkcí, kterými můžeme seznam obsluhovat. Kód ve VB.NET:

' deklarace a inicializace seznam typu "String", který bude sloužit pro ukládání textů
Dim seznam As New System.Collections.Generic.List(Of String)()

' pridat 3 polozky
seznam.Add("Polozka 1")
seznam.Add("Polozka 2")
seznam.Add("Polozka 3")

seznam.Remove("Polozka 2") ' odstranit polozku ekvivalentni textu "Polozka 2"

seznam.Insert(0, "Polozka 0") ' vlozit novou polozku na zacatek

seznam.RemoveAt(2) ' odebrat polozku s indexem 2

seznam.Reverse() ' obratit poradi polozek v seznamu

seznam.Sort() ' seradi polozky v seznamu

Console.WriteLine(seznam(1)) ' vypsat polozku na pozici 1

' projit vsechny polozky seznamu
For Each polozka As String In seznam
    Console.WriteLine(polozka)
Next

' zjistit, zda existuje v seznamu polozka
If seznam.Contains("Polozka 0") Then
    Console.WriteLine("Seznam obsahuje polozku 'Polozka 0'!")
End If

' zjistit pocet polozek
Console.WriteLine("Pocet polozek v seznamu: {0}", seznam.Count)

A v C#:

// deklarace a inicializace seznam typu "String", který bude sloužit pro ukládání textů
System.Collections.Generic.List<String> seznam = new System.Collections.Generic.List<String>();

// pridat 3 polozky
seznam.Add("Polozka 1");
seznam.Add("Polozka 2");
seznam.Add("Polozka 3");
    
seznam.Remove("Polozka 2"); // odstranit polozku ekvivalentni textu "Polozka 2"

seznam.Insert(0, "Polozka 0"); // vlozit novou polozku na zacatek

seznam.RemoveAt(2); // odebrat polozku s indexem 2

seznam.Reverse(); // obratit poradi polozek v seznamu

seznam.Sort(); // seradi polozky v seznamu

Console.WriteLine(seznam[1]); // vypsat polozku na pozici 1

// projit vsechny polozky seznamu
foreach (string polozka in seznam)
{
    Console.WriteLine(polozka);
   }
    
// zjistit, zda existuje v seznamu polozka
if(seznam.Contains("Polozka 0"))
    Console.WriteLine("Seznam obsahuje polozku 'Polozka 0'!");


// zjistit pocet polozek
Console.WriteLine("Pocet polozek v seznamu: {0}", seznam.Count);

Všimněte si, že ve VB.NET se generický třída používá ve formátu:

List(Of String) 

V v C# je to:

List<string>

Nespornou výhodou generických kolekcí je především fakt, že jsou silně typové. Tedy funkce Add přebírá jen parametr toho typu, který jsme předali jako generický parametr při deklaraci třídy a zároveň při čtení ze seznamu získáváme opět přímo požadovaný datový typ. Oproti tomu klasické kolekce a seznamy ve starších programovacích jazycích dokázaly vracet jen netypový object.

V této sérii jsem psal i o následujících třídách:

  • List
  • Dictionary
  • SortedDictionary a SortedList
  • Queue
  • Stack
  • HashSet
  •  

    hodnocení článku

    1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

     

    Nový příspěvek

     

    Diskuse: .NET Tip #12: Generické kolekce (1/7) - List

    Dobrý den,

    už nějakou dobu řešim jak vytvořit seznam s odkazy na komponenty.

    Pro vysvětlení: Mám komponentu, která mi zprostředkovává přístup k api. Tyto komponenty však musím ještě inicializovat na stisk tlačítka. Otázkou je, zda jde vytvořit seznam(např. ve Form1) a v komponentě vlastnost, v které by se určilo k jakému seznamu patří, pak by se v konstruktoru přidal odkaz na danou kopmponentu do seznamu.

    Pokud vytvořím odkaz na jednu komponentu tak je vše OK

    	Private _PLCValRead As ComPLCBit
    	<Category("PLC API"), DisplayName("PLC register Read")> _
    	Public Property PlcRegRead() As ComPLCBit
    		Get
    			Return _PLCValRead
    		End Get
    		Set(ByVal value As ComPLCBit)
    			_PLCValRead = value
    		End Set
    	End Property
    
    

    a při otevření této vlastnosti se mi zobrazí seznam vložených komponent, z kterých si mohu jednu vybrat.

    Při použití Listu

    	Private _seznamAdr As List(Of ComPLCBit)
    	Public Property SeznamAdr() As List(Of ComPLCBit)
    		Get
    			Return _seznamAdr
    		End Get
    		Set(ByVal value As List(Of ComPLCBit))
    			_seznamAdr = value
    		End Set
    	End Property
    
    

    se při přidání komponenty do seznamu vytvoří zcela nová.

    Děkuji za jakýkoliv nápad

    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    Diskuse: .NET Tip #12: Generické kolekce (1/7) - List

    Dobrý den, zajímalo by mě jak uvnitř struktury definovat pole, seznam atp. a nebo ještě lépe, jak uvnitř jedné struktury vytvořit pole obsahující jinou mou strukturu. Tady je příklad.

    structure Triplet
    dim value as string
    dim startTime as dateTime
    dim endTime as dateTime
    End Structure
    
    structure Entry
    dim severity as Integer
    dim status() as Triplet
    End Structure
    
    '..................
    dim myEntry as New Entry
    myEntry.severity=5
    myEntry.status(0).value="run"
    myEntry.status(0).startTime=CDate(Format(Now,"dd/MM/yyyy"))
    myEntry.status(0).endTime=CDate(Format(Now,"dd/MM/yyyy"))
    myEntry.status(1).value="wait"
    

    Tak tohle bohužel nefunguje. Jak jinak vytvořit takovou strukturu navíc, abych nebyl omezen velikostí pole?

    Děkuji moc za případnou odpověď.

    Petr

    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    To bude tím, že pole není inicializované (nemá žádnou velikost). Zkuste právě na tohle použít List:

    Structure Entry
       Dim severity As Integer
       Dim status As List(Of Triplet)
    End Structure
    
    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    Dobrý den,

    tohle jsem zkoušel ale neumím to potom naplnit.

        Structure TripletStr
            Dim value As String
            Dim startDate As DateTime
            Dim endDate As DateTime
        End Structure
    
        Structure Entry
            Dim nr As String
            Dim status As List(Of TripletStr)
        End Structure
    
    Private Sub Form1_Load....
    Dim iss As New Entry()
    Dim stat As New TripletStr()
    
    iss.nr = "12345678-01"
    stat.value = "run"
    stat.startDate = CDate(Format(Now, "dd/MM/yyyy"))
    stat.endDate = CDate(Format(Now, "dd/MM/yyyy"))
    iss.status.Add(stat) ' NullReferenceException was unhandled
    end Sub
    

    Pokud chci naplnit iss.status, hlásí mi to chybu. Nevěděl by jste co s tím?

    Petr

    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    Protože nemáte tuto proměnnou inicializovanou. iss.status je prázdný. Je potřeba ho před plněním vytvořit:

    Private Sub Form1_Load....
    Dim iss As New Entry()
    Dim stat As New TripletStr()
    
    iss.nr = "12345678-01"
    stat.value = "run"
    stat.startDate = CDate(Format(Now, "dd/MM/yyyy"))
    stat.endDate = CDate(Format(Now, "dd/MM/yyyy"))
    iss.status = New List(Of TripletStr)() ' inicializovat objekt
    iss.status.Add(stat) ' vše už proběhne ok
    end Sub
    
    
    nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

    Aha, děkuju moc. Nevěděl jsem kam to New nacpat.

    Jinak co se vašich článků týká, doufám že jich bude přibývat, jsou krátké a výstižné, je v nich vše co pro dané téma mohu použít.

    Děkuju moc!

    Petr

    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    Diskuse: .NET Tip #12: Generické kolekce (1/7) - List

    Dobrý den,

    přemýšlím jak nejlépe a efektivně načítat nějaká data z textového dokumentu a napadlo mě využití seznamu.

     Structure Osoba
            Dim Jmeno, Prijmeni As String
            Dim Vek As Byte
        End Structure
    

    ve Form1_Load pak:

    Dim seznam As New System.Collections.Generic.List(Of Osoba)()
            Dim os As New Osoba
            os.Jmeno = "Jan"
            os.Prijmeni = "Beran"
            os.Vek = 30
            seznam.Add(os)
    
            os.Jmeno = "Pavel"
            os.Prijmeni = "Soukup"
            os.Vek = 50
            seznam.Add(os)
    

    Zajímalo by mě, zda je možné nyní použít sort seznamu podle položky struktury, nebo odstranění záznamu podle položky.

    Něco jako seznam.Jmeno.sort() nebo seznam.Prijmeni.remove("Soukup")

    Toto ale nefunguje.

    Děkuji,

    Petr

    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    Takto jednoduché to bohužel nebude.

    Sortování je popsané v tomto článku:

    http://www.vbnet.cz/blog-clanek--170-net...

    A mazání znamená procházet záznam po záznamu a v případě shody smazat. Také je možné použít Linq k vybrání záznamů ke smazání, ale asi rozebírat nebudu, princip stejně zůstane stejný.

    nahlásit spamnahlásit spam 0 odpovědětodpovědět

    Děkuji za rychlou odpověď.

    Ještě by mě zajímalo jaká je běžná praxe v načítání dat takového charakteru, aby se s nimi později manipulovalo co nejjednodušeji a aby to v případě tisíce položek nijak nezpomalovalo.

    Petr

    nahlásit spamnahlásit spam 0 odpovědětodpovědět
                           
    Nadpis:
    Antispam: Komu se občas házejí perly?
    Příspěvek bude publikován pod identitou   anonym.

    Nyní zakládáte pod článkem nové diskusní vlákno.
    Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

    Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

     

    • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
      Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
    • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

    přihlásit pomocí externího účtu

    přihlásit pomocí jména a hesla

    Uživatel:
    Heslo:

    zapomenuté heslo

     

    založit nový uživatelský účet

    zaregistrujte se

     
    zavřít

    Nahlásit spam

    Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

    Nahlásit Zrušit

    Chyba

    zavřít

    feedback