Czy listy dwuwymiarowe są możliwe w języku C #?

89

Chciałbym utworzyć wielowymiarową listę. Dla porównania, pracuję nad analizatorem listy odtwarzania.

Mam plik / listę plików, które mój program zapisuje na standardowej liście. Jeden wiersz z pliku w każdym wpisie listy.

Następnie analizuję listę za pomocą wyrażeń regularnych, aby znaleźć określone wiersze. Niektóre dane / wyniki z wierszy muszą zostać umieszczone na nowej wielowymiarowej liście; ponieważ nie wiem, ile wyników / danych otrzymam, nie mogę użyć tablicy wielowymiarowej.

Oto dane, które chcę wstawić:

Lista
(
    [0] => Lista
        (
            [0] => Identyfikator ścieżki
            [1] => Imię
            [2] => Artysta
            [3] => Album
            [4] => Licznik gier
            [5] => Licznik pominięć

        )
    [1] => Lista
        (
I tak dalej....

Prawdziwy przykład:

Lista
(
    [0] => Lista
        (
            [0] => 2349
            [1] => Najlepszy czas w Twoim życiu
            [2] => Daft Punk
            [3] => W końcu człowiek
            [4] => 3
            [5] => 2

        )
    [1] => Lista
        (

Więc tak, mlist [0] [0] pobierze TrackID z utworu 1, mlist [1] [0] z utworu 2 itd.

Ale mam ogromne problemy z tworzeniem wielowymiarowej listy. Do tej pory wymyśliłem

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

Ale tak naprawdę nie miałem dużo większych postępów :(

CasperT
źródło

Odpowiedzi:

138

Cóż, z pewnością możesz użyć miejsca, w List<List<string>>którym napiszesz:

List<string> track = new List<string>();
track.Add("2349");
track.Add("The Prime Time of Your Life");
// etc
matrix.Add(track);

Ale dlaczego miałbyś to zrobić zamiast budować własną klasę reprezentującą utwór, z właściwościami Track ID, Name, Artist, Album, Play Count i Skip Count? Następnie wystarczy List<Track>.

Jon Skeet
źródło
1
Hmm, naprawdę nie jestem pewien, jak to zrobić! Rozglądałem się za utworzeniem klasy do samodzielnej obsługi playlist, ale myślę, że to lepszy pomysł.
CasperT
Poza tym, czy nie wymagałoby to wiedzy, ile utworów ostatecznie utworzę / przechowam?
CasperT
2
Nie, ponieważ List <Track> nadal ma rozmiar dynamiczny. Można by analizować dane na jednym torze, należy utworzyć nową instancję toru, dodać go do listy <ścieżkę>, a następnie analizować następnego, itd.
Jon Skeet
caspert, List <T> śledzi liczbę obiektów, które przechowuje dla Ciebie. Możesz sprawdzić kwotę, dzwoniąc do List <T> .Count
Spoike
3
@CasperT Zrób to, co wielu sugerowało i zrób Trackzajęcia. Znacznie łatwiej będzie zrozumieć / utrzymać kod. Jeśli reprezentujesz ścieżkę jako listę ciągów, wówczas indeksy indeces, w których przechowujesz określony atrybut, będą musiały zostać zsynchronizowane we wszystkich instancjach, w których próbujesz uzyskać dostęp do informacji o ścieżce. Implementacja za każdym razem będzie żmudna i niemożliwa do debugowania. Proszę, dla własnego dobra zajrzyjcie na zajęcia. :)
Alexander Kondratskiy
103

Jak wspomniał Jon Skeet , możesz to zrobić za pomocą List<Track>. Klasa Track wyglądałaby mniej więcej tak:

public class Track {
    public int TrackID { get; set; }
    public string Name { get; set; }
    public string Artist { get; set; }
    public string Album { get; set; }
    public int PlayCount { get; set; }
    public int SkipCount { get; set; }
}

Aby utworzyć listę utworów List<Track>, po prostu zrób to:

var trackList = new List<Track>();

Dodawanie utworów może być tak proste, jak to:

trackList.add( new Track {
    TrackID = 1234,
    Name = "I'm Gonna Be (500 Miles)",
    Artist = "The Proclaimers",
    Album = "Finest",
    PlayCount = 10,
    SkipCount = 1
});

Dostęp do utworów można uzyskać za pomocą operatora indeksowania:

Track firstTrack = trackList[0];

Mam nadzieję że to pomoże.

Spoike
źródło
4
Jeśli chcesz być naprawdę sprytny, Track może być również strukturą. ;)
Spoike
3
Nie z podaną definicją ... Struktury powinny mieć rozmiar instancji mniejszy niż 16 bajtów ...
Ian
@Ian: Hmm. Nie byłem tego świadomy. Szybko sprawdziłem pod kątem tego dokument MSDN i okazuje się, że struktury muszą mieć mniej niż 16 bajtów. Dzięki za wskazanie tego.
Spoike
14
Nie muszą , to tylko zalecenie. Naprawdę nie ma to większego znaczenia; wybierz strukturę, jeśli potrzebujesz semantyki wartości, w przeciwnym razie po prostu klasa. Jeśli nie wiesz, skorzystaj z klasy.
jason
@Spoike: jak używać listy wewnątrz pętli 2 for, jeśli chcesz dodać dane obecne w jakimś wierszu podczas iteracji w pętli. Na przykład:for(i=0;i< length; i++) { for(j=0;j<length2;j++) {// what should be written here to get the values from a 2d array // to this 2d list } }
Sandeep
35

To najłatwiejszy sposób, w jaki znalazłem to zrobić.

List<List<String>> matrix= new List<List<String>>(); //Creates new nested List
matrix.Add(new List<String>()); //Adds new sub List
matrix[0].Add("2349"); //Add values to the sub List at index 0
matrix[0].Add("The Prime of Your Life");
matrix[0].Add("Daft Punk");
matrix[0].Add("Human After All");
matrix[0].Add("3");
matrix[0].Add("2");

Pobieranie wartości jest jeszcze łatwiejsze

string title = matrix[0][1]; //Retrieve value at index 1 from sub List at index 0
Jordan LaPrise
źródło
4
Chociaż wcześniejsza sugestia dotycząca klasy Track była najlepsza dla wymagań OP, TO rozwiązanie jest dla mnie najlepsze do zbudowania dwuwymiarowej siatki obiektów. Dzięki!
CigarDoug
2
Tak, to jest najbardziej proste i eleganckie rozwiązanie, cieszę się, że pomogłem!
Jordan LaPrise
1
Proste i pomocne! Dziękuję Ci!
Dov Miller
12

inna praca, wokół której korzystałem, to ...

List<int []> itemIDs = new List<int[]>();

itemIDs.Add( new int[2] { 101, 202 } );

Biblioteka, nad którą pracuję, ma bardzo formalną strukturę klas i nie chciałem efektywnie dodawać tam dodatkowych rzeczy, aby mieć przywilej nagrania dwóch „powiązanych” intów.

Polega na wprowadzeniu przez programistę tylko tablicy 2 pozycji, ale ponieważ nie jest to typowy element, myślę, że działa.

Paul Jamison
źródło
2

Możesz też ... zrobić w ten sposób,

List<List<Object>> Parent=new  List<List<Object>>();

List<Object> Child=new List<Object>();
child.Add(2349);
child.Add("Daft Punk");
child.Add("Human");
.
.
Parent.Add(child);

jeśli potrzebujesz innego elementu (dziecka), utwórz nową instancję dziecka,

Child=new List<Object>();
child.Add(2323);
child.Add("asds");
child.Add("jshds");
.
.
Parent.Add(child);
DDK
źródło
2

Oto jak zrobić listę dwuwymiarową

        // Generating lists in a loop.
        List<List<string>> biglist = new List<List<string>>();

        for(int i = 1; i <= 10; i++)
        {
            List<string> list1 = new List<string>();
            biglist.Add(list1);
        }

        // Populating the lists
        for (int i = 0; i < 10; i++)
        {
            for(int j = 0; j < 10; j++)
            {
                biglist[i].Add((i).ToString() + " " + j.ToString());
            }
        }

        textbox1.Text = biglist[5][9] + "\n";

Należy pamiętać o niebezpieczeństwie związanym z uzyskaniem dostępu do niezamieszkałej lokalizacji.

Ben
źródło
1

Użyłem:

List<List<String>> List1 = new List<List<String>>
var List<int> = new List<int>();
List.add("Test");
List.add("Test2");
List1.add(List);
var List<int> = new List<int>();
List.add("Test3");
List1.add(List);

to równa się:

List1
(
[0] => List2 // List1[0][x]
    (
        [0] => Test  // List[0][0] etc.
        [1] => Test2

    )
[1] => List2
    (
        [0] => Test3
SoIAS
źródło
To jest dla mnie pomocne! Dziękuję Ci!
Dov Miller
0

Możesz również skorzystać z DataTable - możesz wtedy zdefiniować liczbę kolumn i ich typy, a następnie dodać wiersze http://www.dotnetperls.com/datatable

Val
źródło
Lepiej trzymaj się tego List<Track>podejścia i używaj a BindingSource, po prostu dodając DataSource do swojego DataGridViewtypu, Trackaby obsługiwać silnie wpisane klasy w kodzie i łatwą do skonfigurowania wizualizację ścieżek w widoku siatki danych.
Oliver
Zgoda, ale czasami nie chcesz wyświetlać danych od razu i nie chcesz tworzyć jeszcze jednej klasy tylko po to, aby używać ich tylko w jednym miejscu, więc wolę korzystać z istniejącego rozwiązania. ... Chciałem tylko wskazać jeszcze jeden sposób rozwiązania tego problemu! ;)
Val
0

Oto małe coś, co zrobiłem jakiś czas temu dla silnika gry, nad którym pracowałem. Był używany jako lokalny uchwyt zmiennej obiektu. Zasadniczo używasz jej jako zwykłej listy, ale zawiera ona wartość w miejscu, w jakim znajduje się nazwa ciągu (lub identyfikator). Trochę modyfikacji, a będziesz miał swoją listę 2D.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GameEngineInterpreter
{
    public class VariableList<T>
    {
        private List<string> list1;
        private List<T> list2;

        /// <summary>
        /// Initialize a new Variable List
        /// </summary>
        public VariableList()
        {
            list1 = new List<string>();
            list2 = new List<T>();
        }

        /// <summary>
        /// Set the value of a variable. If the variable does not exist, then it is created
        /// </summary>
        /// <param name="variable">Name or ID of the variable</param>
        /// <param name="value">The value of the variable</param>
        public void Set(string variable, T value)
        {
            if (!list1.Contains(variable))
            {
                list1.Add(variable);
                list2.Add(value);
            }
            else
            {
                list2[list1.IndexOf(variable)] = value;
            }
        }

        /// <summary>
        /// Remove the variable if it exists
        /// </summary>
        /// <param name="variable">Name or ID of the variable</param>
        public void Remove(string variable)
        {
            if (list1.Contains(variable))
            {
                list2.RemoveAt(list1.IndexOf(variable));
                list1.RemoveAt(list1.IndexOf(variable));
            }
        }

        /// <summary>
        /// Clears the variable list
        /// </summary>
        public void Clear()
        {
            list1.Clear();
            list2.Clear();
        }

        /// <summary>
        /// Get the value of the variable if it exists
        /// </summary>
        /// <param name="variable">Name or ID of the variable</param>
        /// <returns>Value</returns>
        public T Get(string variable)
        {
            if (list1.Contains(variable))
            {
                return (list2[list1.IndexOf(variable)]);
            }
            else
            {
                return default(T);
            }
        }

        /// <summary>
        /// Get a string list of all the variables 
        /// </summary>
        /// <returns>List string</string></returns>
        public List<string> GetList()
        {
            return (list1);
        }
    }
}
Joe Horrell
źródło