104

I'd like to set up a multidimensional list. For reference, I am working on a playlist analyzer.

I have a file/file-list, which my program saves in a standard list. One line from the file in each list entry.

I then analyze the list with regular-expressions to find specific lines. Some of the data/results from the lines needs to be put into a new multidimensional list; since I don't know how many results/data I'll end up with, I can't use a multidimensional array.

Here is the data I want to insert:

List
(
    [0] => List
        (
            [0] => Track ID
            [1] => Name
            [2] => Artist
            [3] => Album
            [4] => Play Count
            [5] => Skip Count

        )
    [1] => List
        (
And so on....

Real Example:

List
(
    [0] => List
        (
            [0] => 2349
            [1] => The Prime Time of Your Life
            [2] => Daft Punk
            [3] => Human After All
            [4] => 3
            [5] => 2

        )
    [1] => List
        (

So yeah, mlist[0][0] would get TrackID from song 1, mlist[1][0] from song 2 etc.

But I am having huge issues creating a multidimensional list. So far I have come up with

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

But I haven't really had much more progress :(

guntbert
  • 536
  • 6
  • 19
CasperT
  • 3,425
  • 11
  • 41
  • 56

12 Answers12

157

Well you certainly can use a List<List<string>> where you'd then write:

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

But why would you do that instead of building your own class to represent a track, with Track ID, Name, Artist, Album, Play Count and Skip Count properties? Then just have a List<Track>.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Hmm, I am honestly not sure how to do that! I looked at setting up a class for playlist handling alone, but I guess that is a better idea. – CasperT Mar 20 '09 at 08:13
  • Also, wouldn't it require knowing how many tracks I will eventually create/store? – CasperT Mar 20 '09 at 08:17
  • 3
    No, because the List is still dynamically sized. You'd parse the data for one track, create a new instance of Track, add it to the List and then parse the next one, etc. – Jon Skeet Mar 20 '09 at 08:21
  • caspert, the List keeps track of the amount of objects it stores for you. You can access the amount by calling List.Count – Spoike Mar 20 '09 at 08:22
  • 4
    @CasperT Please do what many have suggested and make a `Track` class. It will be much easier to understand/maintain the code. If you represent a track as a list of strings, then the indeces where you store a particular attribute will have to be synchronised across _all instances_ where you try to access track information. It will become tedious to implement each time and impossible to debug. Please, for your own sake, look into classes. :) – Alexander Kondratskiy Apr 11 '11 at 13:59
113

As Jon Skeet mentioned you can do it with a List<Track> instead. The Track class would look something like this:

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

And to create a track list as a List<Track> you simply do this:

var trackList = new List<Track>();

Adding tracks can be as simple as this:

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

Accessing tracks can be done with the indexing operator:

Track firstTrack = trackList[0];
starball
  • 20,030
  • 7
  • 43
  • 238
Spoike
  • 119,724
  • 44
  • 140
  • 158
  • 4
    If you want to be really savvy, Track could also be a struct. ;) – Spoike Mar 20 '09 at 08:23
  • 4
    Not with the definition you've given... Structs should have an instance size of less than 16bytes... – Ian Mar 20 '09 at 08:24
  • @Ian: Hmm. I wasn't aware of that. Quickly checked MSDN doc for that and it turns out structs need to be less than 16 bytes. Thanks for pointing it out. – Spoike Mar 20 '09 at 08:37
  • 15
    They don't _need_ to be, it's just a recommendation. It doesn't really matter that much; choose struct if you need value semantics otherwise just class. If you don't know, use a class. – jason Feb 02 '10 at 19:42
39

This is the easiest way i have found to do it.

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

To retrieve values is even easier

string title = matrix[0][1]; //Retrieve value at index 1 from sub List at index 0
Jordan LaPrise
  • 1,088
  • 1
  • 11
  • 20
14

another work around which i have used was...

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

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

The library i'm working on has a very formal class structure and i didn't wan't extra stuff in there effectively for the privilege of recording two 'related' ints.

Relies on the programmer entering only a 2 item array but as it's not a common item i think it works.

paul jamison
  • 141
  • 1
  • 2
2

Here is how to make a 2 dimensional list

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

Be aware of the danger of accessing a location that is not populated.

niko
  • 3,946
  • 12
  • 26
Ben
  • 21
  • 1
2

You can also..do in this way,

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

if you need another item(child), create a new instance of child,

Child=new List<Object>();
child.Add(2323);
child.Add("asds");
child.Add("jshds");
.
.
Parent.Add(child);
DDK
  • 71
  • 1
  • 8
1

I used:

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

that equals:

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

    )
[1] => List2
    (
        [0] => Test3
SoIAS
  • 21
  • 2
1

You can also use DataTable - you can define then the number of columns and their types and then add rows http://www.dotnetperls.com/datatable

Val
  • 1,548
  • 1
  • 20
  • 36
  • Better stick to the `List` approach and use a `BindingSource`, by simply adding a DataSource to your `DataGridView` of the type `Track` to support strongly typed classes in code and easy to configure visualization of the tracks within the data grid view. – Oliver Feb 13 '13 at 12:17
  • Agreed, but sometimes you don't want to display the data instantly and you don't want to create one more class just to use it in only one place so I prefer to use an existing solution. ...Just wanted to point out one more way to solve this! ;) – Val Mar 06 '13 at 15:37
1

You can create 2D list in C# in this way,

List<List<int>> list = new List<List<int>>{
         new List<int> { 1, 2, 3 },
         new List<int> { 4, 5, 6 },
         new List<int> { 9, 8, 9 }
};
Elikill58
  • 4,050
  • 24
  • 23
  • 45
0

Here's a little something that I made a while ago for a game engine I was working on. It was used as a local object variable holder. Basically, you use it as a normal list, but it holds the value at the position of what ever the string name is(or ID). A bit of modification, and you will have your 2D list.

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

Just because it hasnt been mentioned yet, sometimes I prefer a List<Dictionary<string, string>>. There are cases where I just dont want to make a custom object for whatever reason, and this super simple data structure is pretty flexible. I realize everything is a string which is innefficient, and it forces you to parse and stringify when incrementing the PlayCount, but it might be worth it to some people.

var trackList = new List<Dictionary<string, string>>();

var track = new Dictionary<string, string>();
track.Add("TrackID"  , "1234");
track.Add("Name"     , "I'm Gonna Be (500 Miles)");
track.Add("Artist"   , "The Proclaimers");
track.Add("Album"    , "Finest");
track.Add("PlayCount", "10");
track.Add("SkipCount", "1");
trackList.Add(track);

This actually has a couple benefits over a custom object, namely, you can add a new key value to some of the tracks, without needing to add it to all the tracks, and the existing code will still work without recompiling. Obviously you have to recompile if you write code to do something with those new keys, but its not required. Second, if you ever store the data in a file you probably want it to be human readable (i would) in which case its all strings anyway. You can add, remove, or modify keys or values with a text editor, and this data structure is able to handle it.

rocketsarefast
  • 4,072
  • 1
  • 24
  • 18
0

In C# 7.0, you can initialize it this way:

var tracks = new List<(int trackId,
                       string name,
                       string artist,
                       string album,
                       int playCount,
                       int skipCount)>
{
    ( 2349, "The Prime Time of Your Life", "Daft Punk", "Human After All", 3, 2 )
};

This answer was inspired by:

Stephen Quan
  • 21,481
  • 4
  • 88
  • 75