¿Son posibles las listas bidimensionales en c #?

89

Me gustaría crear una lista multidimensional. Como referencia, estoy trabajando en un analizador de listas de reproducción.

Tengo un archivo / lista de archivos, que mi programa guarda en una lista estándar. Una línea del archivo en cada entrada de la lista.

Luego analizo la lista con expresiones regulares para encontrar líneas específicas. Algunos de los datos / resultados de las líneas deben incluirse en una nueva lista multidimensional ; Como no sé con cuántos resultados / datos terminaré, no puedo usar una matriz multidimensional.

Aquí están los datos que quiero insertar:

Lista
(
    [0] => Lista
        (
            [0] => ID de pista
            [1] => Nombre
            [2] => Artista
            [3] => Álbum
            [4] => Recuento de reproducciones
            [5] => Recuento de saltos

        )
    [1] => Lista
        (
Y así....

Ejemplo real:

Lista
(
    [0] => Lista
        (
            [0] => 2349
            [1] => El mejor momento de tu vida
            [2] => Daft Punk
            [3] => Humano después de todo
            [4] => 3
            [5] => 2

        )
    [1] => Lista
        (

Así que sí, mlist [0] [0] obtendría TrackID de la canción 1, mlist [1] [0] de la canción 2, etc.

Pero estoy teniendo enormes problemas para crear una lista multidimensional. Hasta ahora se me ha ocurrido

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

Pero realmente no he tenido mucho más progreso :(

CasperT
fuente

Respuestas:

139

Bueno, ciertamente puedes usar un lugar List<List<string>>donde luego escribirías:

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

Pero, ¿por qué harías eso en lugar de crear tu propia clase para representar una pista, con las propiedades ID de pista, Nombre, Artista, Álbum, Recuento de reproducción y Recuento de saltos? Entonces solo toma un List<Track>.

Jon Skeet
fuente
1
Hmm, ¡honestamente no estoy seguro de cómo hacer eso! Pensé en configurar una clase para el manejo de listas de reproducción solo, pero creo que es una mejor idea.
CasperT
Además, ¿no requeriría saber cuántas pistas crearé / almacenaré eventualmente?
CasperT
2
No, porque List <Track> todavía tiene un tamaño dinámico. Analizaría los datos de una pista, crearía una nueva instancia de Track, la agregaría a List <Track> y luego analizaría la siguiente, etc.
Jon Skeet
caspert, List <T> realiza un seguimiento de la cantidad de objetos que almacena para usted. Puede acceder a la cantidad llamando a List <T> .Count
Spoike
3
@CasperT Por favor, haga lo que muchos han sugerido y haga una Trackclase. Será mucho más fácil de entender / mantener el código. Si representa una pista como una lista de cadenas, entonces las sangrías en las que almacena un atributo particular deberán sincronizarse en todas las instancias en las que intente acceder a la información de la pista. Se volverá tedioso de implementar cada vez e imposible de depurar. Por favor, por su propio bien, busque clases. :)
Alexander Kondratskiy
103

Como mencionó Jon Skeet , puedes hacerlo con un List<Track>. La clase Track se vería así:

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

Y para crear una lista de pistas List<Track>simplemente haz esto:

var trackList = new List<Track>();

Agregar pistas puede ser tan simple como esto:

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

El acceso a las pistas se puede hacer con el operador de indexación:

Track firstTrack = trackList[0];

Espero que esto ayude.

Spoike
fuente
4
Si quieres ser realmente inteligente, Track también podría ser una estructura. ;)
Spoike
3
No con la definición que ha dado ... Las estructuras deben tener un tamaño de instancia de menos de 16 bytes ...
Ian
@Ian: Hmm. No estaba consciente de eso. Comprobó rápidamente el documento de MSDN para eso y resulta que las estructuras deben tener menos de 16 bytes. Gracias por mencionarlo.
Spoike
14
No es necesario que lo estén, es solo una recomendación. Realmente no importa mucho; elija estructura si necesita semántica de valor, de lo contrario solo clase. Si no lo sabe, use una clase.
jason
@Spoike: cómo usar la lista dentro de un 2 para bucles si desea agregar los datos presentes en alguna fila mientras se itera a través del bucle. Por ejemplo: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

Esta es la forma más fácil que he encontrado para hacerlo.

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

Recuperar valores es aún más fácil

string title = matrix[0][1]; //Retrieve value at index 1 from sub List at index 0
Jordan LaPrise
fuente
4
Aunque la sugerencia anterior sobre una clase Track era la mejor para los requisitos del OP, ESTA solución es la mejor para mí para construir una cuadrícula bidimensional de objetos. ¡Gracias!
CigarDoug
2
Sí, esta es la solución más simple y elegante que he encontrado, ¡me alegro de haber ayudado!
Jordan LaPrise
1
¡Simple y útil! ¡Gracias!
Dov Miller
12

otro trabajo en torno al que he usado fue ...

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

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

La biblioteca en la que estoy trabajando tiene una estructura de clases muy formal y no quería tener material adicional allí de manera efectiva por el privilegio de grabar dos entradas "relacionadas".

Se basa en que el programador ingrese solo una matriz de 2 elementos, pero como no es un elemento común, creo que funciona.

Paul Jamison
fuente
2

También puedes ... hacerlo de esta manera,

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

si necesita otro elemento (hijo), cree una nueva instancia de hijo,

Child=new List<Object>();
child.Add(2323);
child.Add("asds");
child.Add("jshds");
.
.
Parent.Add(child);
DDK
fuente
2

Aquí se explica cómo hacer una lista bidimensional

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

Tenga en cuenta el peligro de acceder a un lugar que no está poblado.

Ben
fuente
1

Solía:

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

eso es igual a:

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

    )
[1] => List2
    (
        [0] => Test3
SoIAS
fuente
¡Esto es útil para mí! ¡Gracias!
Dov Miller
0

También puede usar DataTable: puede definir el número de columnas y sus tipos y luego agregar filas http://www.dotnetperls.com/datatable

Val
fuente
Es mejor ceñirse al List<Track>enfoque y utilizar un BindingSource, simplemente agregando un DataSource a su DataGridViewtipo Trackpara admitir clases fuertemente tipadas en el código y una visualización fácil de configurar de las pistas dentro de la vista de cuadrícula de datos.
Oliver
De acuerdo, pero a veces no desea mostrar los datos al instante y no desea crear una clase más solo para usarla en un solo lugar, así que prefiero usar una solución existente. ... ¡Solo quería señalar una forma más de resolver esto! ;)
Val
0

Aquí hay algo que hice hace un tiempo para un motor de juego en el que estaba trabajando. Se utilizó como un contenedor de variable de objeto local. Básicamente, lo usa como una lista normal, pero mantiene el valor en la posición de lo que sea el nombre de la cadena (o ID). Un poco de modificación y tendrás tu lista 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
fuente