字符串到分层列表

时间:2015-09-25 11:06:12

标签: c# .net hierarchical-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
...

我需要将其转换为以下类型的列表:

public class Category {
    public int Id { get; set; }
    public string Name { get; set; }
    public Category Parent { get; set; }
}

类别名称不能包含 - 或>字符。

E.g。以下一行:

  

3 - 第一级1>第二级1>第三级

将一个类别添加到列表中,其id为3,名称为“Third Level 1”,Parent将指向名称为“Second Level 1”的类别(在上面的示例中id = 2,不是id = 6)。

请注意,可能有多个具有相同名称的类别,因此需要查找整个路径以获取父级。

到目前为止,我已经设法将每行的字符串拆分,然后对于每一行我对连字符进行另一次拆分以获取id和完整的类别名称。然后我可以对大于符号进行进一步拆分以检索类别部分。我拿最后一部分来获取类别名称,如果有多个部分,我知道我需要查找父类。

这是我迷失的地方,因为我现在需要使用其余的部分来计算父母,考虑到上面的多个类别可能具有相同的名称

如果有人能告诉我这是怎么做的,我会很感激。感谢

2 个答案:

答案 0 :(得分:2)

如果我正确理解了您的问题陈述,则此代码应该有效

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

<强>更新

澄清之后,这是更改后的代码

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

对于此测试数据:

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

这是查找值(如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
          }
        }
      }
    }
  }
]

答案 1 :(得分:2)

因为我更喜欢它,我让你的课堂不可变:

searchResult

通过使用此代码,我得到了所有可用类别的平面列表,其中每个类别都获得对其父级的引用:

public class Category
{
    public int Id { get; private set; }
    public string Name { get; private set; }
    public Category Parent { get; private set; }

    public Category(int id, string name, Category parent)
    {
        Id = id;
        Name = name;
        Parent = parent;
    }

    public override string ToString()
    {
        return Id + " " + Name
            + (Parent == null ? String.Empty : (Environment.NewLine + "   Parent: " + Parent));
    }
}

仅用于可视化调用:

var categories = new Dictionary<String, Category>(StringComparer.InvariantCultureIgnoreCase);

using (var reader = new StringReader(_SampleData))
{
    string line;

    while ((line = reader.ReadLine()) != null)
    {
        if (String.IsNullOrWhiteSpace(line))
            continue;

        var elements = line.Split('-');
        var id = int.Parse(elements[0]);
        var name = elements[1].Trim();
        var index = name.LastIndexOf('>');
        Category parent = null;

        if (index >= 0)
        {
            var parentName = name.Substring(0, index).Trim();
            categories.TryGetValue(parentName, out parent);
        }

        var category = new Category(id, name, parent);
        categories.Add(category.Name, category);
    }
}

输出结果为:

foreach (var item in categories.Values)
{
    Console.WriteLine(item);
}