Reputation: 2901
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.
Upvotes: 1
Views: 3189
Reputation: 1
To store the data in a suitable data structure in C#, use a nested dictionary:
Outer Dictionary: Dictionary<int, Dictionary<string, object>> to map object numbers to their attributes. Inner Dictionary: Dictionary<string, object> to map attribute keys to their values.
var data = new Dictionary<int, Dictionary<string, object>>
{
{ 1, new Dictionary<string, object> { { "a", 10 }, { "b", "xyz" }, { "c", 40 } } },
{ 12, new Dictionary<string, object> { { "a", 20 }, { "b", "os" } } },
{ 8, new Dictionary<string, object> { { "a", "example1" }, { "b", "example2" } } }
};
// Accessing data example:
foreach (var obj in data)
{
Console.WriteLine($"Object {obj.Key}:");
foreach (var attr in obj.Value)
{
Console.WriteLine($" {attr.Key} -> {attr.Value}");
}
}
Upvotes: 0
Reputation: 28917
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.
// 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.
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);
}
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. :)
(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")
.
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);
}
(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);
}
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.
Upvotes: 3
Reputation: 17119
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.
Upvotes: 2
Reputation: 21241
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.
Upvotes: 0
Reputation: 10423
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.
Upvotes: 0