views:

337

answers:

4

I have data like..

1 -> a 10
     b xyz
     c 40 
12 -> a 20
     b os 
8 -> ..............

how to store this data in data structure. which DS is suitable for it in C#.

1,12,8 are the object no. & a,b,c are the there attribute key & value pair.

it is internal file representation of .. file. So i want to store it for further manipulation operations.

+1  A: 

a Dictionary<int,Dictionary<string,string>>

Edit: if you only have 'a' 'b' 'c' as the keys, you'd just use string[] rec = new string[3] instead of a dictionary.

Yin Zhu
how is a string going to hold the 3 items on the left?
Mitch Wheat
@Mitch a int holds the index numbers 1, 12, 8 etc
Yin Zhu
@Mitch, his outer Dictionary is keyed on int, and all three items on the left are ints.
ProfK
A: 

Data content itself is just one aspect of data structure choice. A more important guideline is how you will create, manipulate, and access the data.

List<Dictionary<char, object>> will handle ordering if you want to access 1, 2, 3, etc.. in an ordered fashion and allow the second level to be any type of content you want.

Dictionary<int, Dictionary<string, string>> would allow you to do fast lookups of any top level 1, 2, 3, etc... and would assume that the a / 10, b / xyz, etc... are always encoded as strings.

It would help if you told us how you were using this data.

Michael Greene
A: 

Raw structure you could use:

Dictionary<int, Dictionary<char, object>> //or
Dictionary<int, Dictionary<string, object>> //the more common construct, or
Dictionary<int, Dictionary<string, string>> //would require casting on some objects

This probably wont be optimal for your situation though, depending on how you intend to search/access this.

Depending on the meaning of your data a specific class implementation and a Dictionary implementation might work better.

GrayWizardx
+2  A: 

Anonymous classes and implicitly typed arrays make code shorter by doing away with the need for class templates and explicit types in source code. A big drawback of this feature is elements are read-only.

No additional code is missing from this example, except to paste it into your source file.

A concise, anonymous data structure

    // Strongly-typed anonymous data structure.

    var allData = new[] { // array of parts
        new { Num = 1, Details = new[] { // each part is keyed by object num
                new {KeyChar = 'a', StringValue = "10"} , // key/value pair details
                new {KeyChar = 'b', StringValue = "xyz"} ,
                new {KeyChar = 'c', StringValue = "40"} } 
        },
        new { Num = 12, Details = new[] { 
                new {KeyChar = 'a', StringValue = "20"} ,
                new {KeyChar = 'b', StringValue = "os"} }
        },
        new { Num = 8, Details = new[] { 
            new {KeyChar = 'n', StringValue = "etc..."} }
        }
    };

The Types are automatically inferred by your consistent data declarations and generated into IL by the C# 3.x+ compiler.

Sample Usage

iterating over your data structure and printing it ....

    foreach (var part in allData) {
        Console.WriteLine("Object #" + part.Num + " contains the details: ");
        foreach (var detail in part.Details)
            Console.WriteLine(" - key: " + detail.KeyChar + ", value: " + detail.StringValue);
    }

Stipulations

  • var, for implicitly typed variables, cannot be used at the class scope (i.e. to make fields) - it is restricted to method scope (i.e. as local variables).

  • There are some things to watch out for when using anonymous types, for example: Can't return anonymous type from method? Really?

  • The MSDN documentation describes some additional behaviour and "Gotchas".

    - Anonymous instances are read-only, so you will need a different way to store and persist modifications. This may render it useless for your requirements.

  • However, it was fun to include this answer as an option because I learned something new today if nothing else. :)


Edit/Update: Writable version

(modification to make an equivalent writable data structure)

An equivalent writable version of the above data structure is the following, using System.Collections.Generic;:

// Initialization (present data is read/writable)
Dictionary<int, List<Detail>> manageableData = new Dictionary<int, List<Detail>>() 
{
    {1, new List<Detail>() { 
        new Detail {KeyChar = 'a', StringValue="10"},
        new Detail {KeyChar = 'b', StringValue="xyz"}, 
        new Detail {KeyChar = 'c', StringValue="40"}  
        } },

    {12, new List<Detail>() { 
        new Detail {KeyChar = 'a', StringValue="20"},
        new Detail {KeyChar = 'b', StringValue="os"}
        } }
};


// Can continue populating after initialization. E.g...
manageableData.Add(8, new List<Detail>() {
        new Detail {KeyChar = 'n', StringValue="etc..."},
        new Detail {KeyChar = 'z', StringValue="etc..."}
});

A small helper class is declared to make initialization of detail data more readable; the Detail helper class replaces what could simply be KeyValuePair<char, string>. According to taste.

public class Detail {
    public char KeyChar { get; set; }
    public string StringValue { get; set; }
}

... effectively allows us to use new Detail {KeyChar = 'b', StringValue="xyz"} for init of detail items instead of new KeyValuePair<char, string>('b', "xyz").

Sample Usage

iterating over your data structure and printing it ....

foreach (var part in manageableData) {
    Console.WriteLine("Object #" + part.Key + " contains the details: ");
    foreach (var detail in part.Value)
        Console.WriteLine(" - key: " + detail.KeyChar + ", value: " + detail.StringValue);
}

Another variation on Writable data structure (less abstract)

(no unneeded abstraction - just raw collections)

Without the custom Detail class, you'd nest your dictionaries like

Dictionary<int, Dictionary<char, string>> data2 = new Dictionary<int, Dictionary<char, string>>() 
{
    {1, new Dictionary<char, string>() { 
        {'a', "10"},
        {'b', "xyz"}, 
        {'c', "40"}  
        } }
};

data2.Add(8, new Dictionary<char,string>() {
        {'n', "etc..."},
        {'z', "etc..."}
});

// SAMPLE USAGE:
// Once again, very minor changes to the mechanism of accessing the data structure:

foreach (var part in data2) {
    Console.WriteLine("Object #" + part.Key + " contains the details: ");
    foreach (var detail in part.Value)
        Console.WriteLine(" - key: " + detail.Key + ", value: " + detail.Value);
}

Name "Aliasing" for readability

This is the plain nested dictionary scenario to store file objects and attributes.

// initialize
Dictionary<int, Dictionary<char, string>> data1 = new Dictionary<int, Dictionary<char, string>>() 
{
    {1, new Dictionary<char, string>() { 
        {'a', "10"},
        {'b', "xyz"}, 
        {'c', "40"}  
        }}
};
// populate 
data1.Add(8, new Dictionary<char, string>() {
    {'n', "etc..."},
    {'z', "etc..."}
    });

Making a more Descriptive/Readable Version

There are ways to make nested data structures more readable. Here's one sample to show some readability differences. Likely this isn't the smartest way because it adds a couple of Types just for the sake of aliasing but nonetheless...

This is the exact same data structure as above but using "aliased" names:

// initialize
FileObjects data2 = new FileObjects() 
{
    {1, new ObjectAttributes() { 
        {'a', "10"},
        {'b', "xyz"}, 
        {'c', "40"}  
        }}
};
// populate 
data2.Add(8, new ObjectAttributes() {
    {'n', "etc..."},
    {'z', "etc..."}
    });

The following "alias" definitions effectively rename the original Generics (through inheritance) to more descriptive types and hide the Type Parameters.

public class ObjectAttributes : Dictionary<char, string> { }
public class FileObjects : Dictionary<int, ObjectAttributes> { }

Likely you'd need more nested data before this type of approach becomes viable.

John K