If I understood your problem statement correctly, this code should work
var strings = File.ReadAllLines(@"C:\YourDirectory\categories.txt");
var categories = new List<Category>();
foreach (var line in strings)
{
var category = new Category(); //line = 3 - First Level 1 -> Second Level 1 -> Third Level 1
var cats = line.Split('>').ToList(); //3 - First Level 1, Second Level 1, Third Level 1
category.Id = int.Parse(cats.First().Split('-').First().Trim()); //3
if (cats.Count > 1)
{
category.Name = cats.Last().Trim(); //Third Level 1
var parentStr = cats.ElementAt(cats.Count - 2).Trim();
if (parentStr.Contains('-'))
parentStr = parentStr.Split('-').Last().Trim();
category.Parent = categories.FirstOrDefault(c => c.Name == parentStr);
}
else
category.Name = cats.First().Split('-').Last().Trim(); //for 1 - First Level 1
categories.Add(category);
}
Update
After clarification, this is the changed code
var lines = File.ReadAllLines(@"C:\YourDirectory\categories.txt");
var lookup = new List<KeyValuePair<List<string>, Category>>(); //key = parents in order
foreach (var line in lines)
{
var category = new Category (); //line = 3 - First Level 1 -> Second Level 1 -> Third Level 1
var parts = line.Split('>').ToList(); //3 - First Level 1, Second Level 1, Third Level 1
category.Id = int.Parse(parts.First().Split('-').First().Trim()); //3
if (parts.Count > 1) //has parent
{
category.Name = parts.Last().Trim(); //Third Level 1
if (parts.Count == 2) //has one level parent
{
var parentStr = parts.First().Split('-').Last().Trim();
if (lookup.Any(l => l.Value.Parent == null && l.Value.Name == parentStr))
{
var parent = lookup.First(l => l.Value.Parent == null && l.Value.Name == parentStr);
category.Parent = parent.Value;
lookup.Add(new KeyValuePair<List<string>,Category>(new List<string> { parent.Value.Name }, category));
}
}
else //has multi level parent
{
var higherAncestors = parts.Take(parts.Count - 2).Select(a => a.Split('-').Last().Trim()).ToList(); //.GetRange(1, parts.Count - 2).Select(a => a.Trim()).ToList();
var parentStr = parts.Skip(parts.Count - 2).First().Trim();
if (lookup.Any(l => MatchAncestors(l.Key, higherAncestors) && l.Value.Name == parentStr))
{
var parent = lookup.First(l => MatchAncestors(l.Key, higherAncestors) && l.Value.Name == parentStr);
category.Parent = parent.Value;
var ancestors = parent.Key.ToList();
ancestors.Add(parent.Value.Name);
lookup.Add(new KeyValuePair<List<string>, Category>(ancestors, category));
}
}
}
else //no parent
{
category.Name = parts.First().Split('-').Last().Trim(); //for 1 - First Level 1
lookup.Add(new KeyValuePair<List<string>,Category> (new List<string>(), category));
}
}
var categories = lookup.Select(l => l.Value); //THIS IS YOUR RESULT
private static bool MatchAncestors(List<string> ancestors1, List<string> ancestors2)
{
if (ancestors1.Count != ancestors2.Count)
return false;
for (int i = 0; i < ancestors1.Count; i++)
{
if (ancestors1[i] != ancestors2[i])
return false;
}
return true;
}
For this test data:
1 - First Level 1
2 - First Level 1 > Second Level 1
3 - First Level 1 > Second Level 1 > Third Level 1
4 - First Level 1 > Second Level 2
5 - First Level 2
6 - First Level 2 > Second Level 1
7 - First Level 2 > Second Level 1 > Third Level 1
8 - First Level 2 > Second Level 1 > Third Level 1 > Fourth Level 1
9 - First Level 1 > Second Level 1 > Third Level 1 > Fourth Level 2
This is the lookup value (as json):
[
{
"Key": [],
"Value": {
"Id": 1,
"Name": "First Level 1",
"Parent": null
}
},
{
"Key": ["First Level 1"],
"Value": {
"Id": 2,
"Name": "Second Level 1",
"Parent": {
"Id": 1,
"Name": "First Level 1",
"Parent": null
}
}
},
{
"Key": ["First Level 1","Second Level 1"],
"Value": {
"Id": 3,
"Name": "Third Level 1",
"Parent": {
"Id": 2,
"Name": "Second Level 1",
"Parent": {
"Id": 1,
"Name": "First Level 1",
"Parent": null
}
}
}
},
{
"Key": ["First Level 1"],
"Value": {
"Id": 4,
"Name": "Second Level 2",
"Parent": {
"Id": 1,
"Name": "First Level 1",
"Parent": null
}
}
},
{
"Key": [],
"Value": {
"Id": 5,
"Name": "First Level 2",
"Parent": null
}
},
{
"Key": ["First Level 2"],
"Value": {
"Id": 6,
"Name": "Second Level 1",
"Parent": {
"Id": 5,
"Name": "First Level 2",
"Parent": null
}
}
},
{
"Key": ["First Level 2","Second Level 1"],
"Value": {
"Id": 7,
"Name": "Third Level 1",
"Parent": {
"Id": 6,
"Name": "Second Level 1",
"Parent": {
"Id": 5,
"Name": "First Level 2",
"Parent": null
}
}
}
},
{
"Key": ["First Level 2","Second Level 1","Third Level 1"],
"Value": {
"Id": 8,
"Name": "Fourth Level 1",
"Parent": {
"Id": 7,
"Name": "Third Level 1",
"Parent": {
"Id": 6,
"Name": "Second Level 1",
"Parent": {
"Id": 5,
"Name": "First Level 2",
"Parent": null
}
}
}
}
},
{
"Key": ["First Level 1","Second Level 1","Third Level 1"],
"Value": {
"Id": 9,
"Name": "Fourth Level 2",
"Parent": {
"Id": 3,
"Name": "Third Level 1",
"Parent": {
"Id": 2,
"Name": "Second Level 1",
"Parent": {
"Id": 1,
"Name": "First Level 1",
"Parent": null
}
}
}
}
}
]