将列表展开为 sub-objects
Unflattening a list to sub-objects
编辑:我意识到我好像马上就来寻求答案。我试着自己做,但我开始相信有一个我不完全理解的机制。我只是无法解决这个问题!
edit2:我用词不当!用"parent"和"children"我不使用"DOM"的意思!这是用于我当前 dev
的 HTML
<body>
<h1>FIRST LEVEL TITLE</h1>
<h4>test</h4>
<h2>SECOND LEVEL TITLE</h2>
<h3>THIRD LEVEL TITLE</h3>
<h4>test</h4>
<h3>THIRD LEVEL TITLE</h3>
<h3>THIRD LEVEL TITLE</h3>
<h2>SECOND LEVEL TITLE</h2>
<h3>THIRD LEVEL TITLE</h3>
<h3>THIRD LEVEL TITLE</h3>
<h4>test</h4>
<h4>test</h4>
</body>
我要创建的 "parent" 和 "child" 层次结构是纯虚拟的(仅存在于我的库中,不存在于 HTML 中)!我的标题标签 没有 嵌套
使用 Bridge.NET 和 Bridge.JQuery 我已经成功地从 HTML 中检索到完整的标题标签列表(h1、h2 等)并将它们存储到一个平面列表中。
现在我试图给这个列表一个层次结构,所以我列表中的每个元素都有一个 属性 "Children" 包含所有直接在它们下面的元素,这些子元素包含其他子元素 ...
如果一个元素与其预期的 parent.
之间没有 intermediate-level 元素,则该元素是直接 children
在列表中
H2, H3, H4,
H4,是H3的child,是H2的child。
但是在列表中
H2, H4, H3,
H3 和 H4 是 H2 的 children
示例:
H1 - FIRST LEVEL TITLE
H4 - test
H2 - SECOND LEVEL TITLE
H3 - THIRD LEVEL TITLE
H4 - test
H3 - THIRD LEVEL TITLE
H3 - THIRD LEVEL TITLE
H2 - SECOND LEVEL TITLE
H3 - THIRD LEVEL TITLE
H3 - THIRD LEVEL TITLE
H4 - test
H4 - test
变成
H1 - FIRST LEVEL TITLE
--->H4 - test
--->H2 - SECOND LEVEL TITLE
--->--->H3 - THIRD LEVEL TITLE
--->--->H4 - test
--->--->--->H3 - THIRD LEVEL TITLE
--->--->--->H3 - THIRD LEVEL TITLE
--->H2 - SECOND LEVEL TITLE
--->--->H3 - THIRD LEVEL TITLE
--->--->H3 - THIRD LEVEL TITLE
--->--->H4 - test
--->--->H4 - test
平面列表中的每个标题定义如下(可以进行任何修改以帮助实现我想要的)
internal class Title
{
public TitleLevel Level { get; set; }
public string Value { get; set; }
public IEnumerable<Title> Children { get; set; }
/* removed irrelevant code */
}
internal enum TitleLevel
{
H6,
H5,
H4,
H3,
H2,
H1,
DummyValue // exists for technical reasons, I may ask for advice on that later
}
所以这是我想要的解决方案(取消扁平化列表)
代码确实不漂亮,但是可以用。
是这样叫的
var hierarchyList = GetTitleHierarchy(flatList);
这是定义
/// <summary>
/// Turns a flat list of titles into a list where each element contains a list of it children, themselves containing a list of childre, ...
/// </summary>
/// <param name="titles">A flat list of titles</param>
/// <returns>A "cascading" list of titles</returns>
internal List<Title> GetTitleHierarchy(List<Title> titles)
{
return PutInParent(titles);
}
private List<Title> PutInParent(List<Title> titles)
{
var output = new List<Title>();
for (int i = 0; i < titles.Count; i++)
{
// Copy because if passed by reference we'll get loop-referencing
var title = titles.Get(i).Copy();
var childrenCount = CountChildren(titles, i);
if (childrenCount > 0)
{
var subItems = titles.GetRange(i + 1, childrenCount);
title.Children = PutInParent(subItems);
}
output.Add(title);
i += childrenCount;
}
return output;
}
/// <summary>
/// Returns the number of titles after the current index that should be children of the current element
/// </summary>
/// <param name="titles">the flat list of elements</param>
/// <param name="startIndex">the current position in the list</param>
/// <returns></returns>
internal int CountChildren(List<Title> titles, int startIndex)
{
var clidrenCount = 0;
foreach (var title in titles.Skip(startIndex + 1))
{
if (title.IsLevelLowerThan(titles.Get(startIndex).Level))
break;
clidrenCount++;
}
return clidrenCount;
}
internal class Title
{
public TitleLevel Level { get; set; }
public string Value { get; set; }
public IEnumerable<Title> Children { get; set; }
#region Overrides of Object
public override string ToString()
{
return $"{Level} - {Value}";
}
#endregion
public Title Copy()
{
return new Title
{
Level = Level,
Value = Value,
Children = Children.Select(c => c.Copy())
};
}
public bool IsLevelLowerThan(TitleLevel targetLevel)
{
return (int) Level <= (int) targetLevel;
}
}
internal enum TitleLevel
{
H1 = 1,
H2 = 2,
H3 = 3,
H4 = 4,
H5 = 5,
H6 = 6,
DummyValue = 0
}
编辑:我意识到我好像马上就来寻求答案。我试着自己做,但我开始相信有一个我不完全理解的机制。我只是无法解决这个问题!
edit2:我用词不当!用"parent"和"children"我不使用"DOM"的意思!这是用于我当前 dev
的 HTML<body>
<h1>FIRST LEVEL TITLE</h1>
<h4>test</h4>
<h2>SECOND LEVEL TITLE</h2>
<h3>THIRD LEVEL TITLE</h3>
<h4>test</h4>
<h3>THIRD LEVEL TITLE</h3>
<h3>THIRD LEVEL TITLE</h3>
<h2>SECOND LEVEL TITLE</h2>
<h3>THIRD LEVEL TITLE</h3>
<h3>THIRD LEVEL TITLE</h3>
<h4>test</h4>
<h4>test</h4>
</body>
我要创建的 "parent" 和 "child" 层次结构是纯虚拟的(仅存在于我的库中,不存在于 HTML 中)!我的标题标签 没有 嵌套
使用 Bridge.NET 和 Bridge.JQuery 我已经成功地从 HTML 中检索到完整的标题标签列表(h1、h2 等)并将它们存储到一个平面列表中。 现在我试图给这个列表一个层次结构,所以我列表中的每个元素都有一个 属性 "Children" 包含所有直接在它们下面的元素,这些子元素包含其他子元素 ...
如果一个元素与其预期的 parent.
之间没有 intermediate-level 元素,则该元素是直接 children在列表中 H2, H3, H4,
H4,是H3的child,是H2的child。 但是在列表中 H2, H4, H3,
H3 和 H4 是 H2 的 children
示例:
H1 - FIRST LEVEL TITLE
H4 - test
H2 - SECOND LEVEL TITLE
H3 - THIRD LEVEL TITLE
H4 - test
H3 - THIRD LEVEL TITLE
H3 - THIRD LEVEL TITLE
H2 - SECOND LEVEL TITLE
H3 - THIRD LEVEL TITLE
H3 - THIRD LEVEL TITLE
H4 - test
H4 - test
变成
H1 - FIRST LEVEL TITLE
--->H4 - test
--->H2 - SECOND LEVEL TITLE
--->--->H3 - THIRD LEVEL TITLE
--->--->H4 - test
--->--->--->H3 - THIRD LEVEL TITLE
--->--->--->H3 - THIRD LEVEL TITLE
--->H2 - SECOND LEVEL TITLE
--->--->H3 - THIRD LEVEL TITLE
--->--->H3 - THIRD LEVEL TITLE
--->--->H4 - test
--->--->H4 - test
平面列表中的每个标题定义如下(可以进行任何修改以帮助实现我想要的)
internal class Title
{
public TitleLevel Level { get; set; }
public string Value { get; set; }
public IEnumerable<Title> Children { get; set; }
/* removed irrelevant code */
}
internal enum TitleLevel
{
H6,
H5,
H4,
H3,
H2,
H1,
DummyValue // exists for technical reasons, I may ask for advice on that later
}
所以这是我想要的解决方案(取消扁平化列表)
代码确实不漂亮,但是可以用。
是这样叫的
var hierarchyList = GetTitleHierarchy(flatList);
这是定义
/// <summary>
/// Turns a flat list of titles into a list where each element contains a list of it children, themselves containing a list of childre, ...
/// </summary>
/// <param name="titles">A flat list of titles</param>
/// <returns>A "cascading" list of titles</returns>
internal List<Title> GetTitleHierarchy(List<Title> titles)
{
return PutInParent(titles);
}
private List<Title> PutInParent(List<Title> titles)
{
var output = new List<Title>();
for (int i = 0; i < titles.Count; i++)
{
// Copy because if passed by reference we'll get loop-referencing
var title = titles.Get(i).Copy();
var childrenCount = CountChildren(titles, i);
if (childrenCount > 0)
{
var subItems = titles.GetRange(i + 1, childrenCount);
title.Children = PutInParent(subItems);
}
output.Add(title);
i += childrenCount;
}
return output;
}
/// <summary>
/// Returns the number of titles after the current index that should be children of the current element
/// </summary>
/// <param name="titles">the flat list of elements</param>
/// <param name="startIndex">the current position in the list</param>
/// <returns></returns>
internal int CountChildren(List<Title> titles, int startIndex)
{
var clidrenCount = 0;
foreach (var title in titles.Skip(startIndex + 1))
{
if (title.IsLevelLowerThan(titles.Get(startIndex).Level))
break;
clidrenCount++;
}
return clidrenCount;
}
internal class Title
{
public TitleLevel Level { get; set; }
public string Value { get; set; }
public IEnumerable<Title> Children { get; set; }
#region Overrides of Object
public override string ToString()
{
return $"{Level} - {Value}";
}
#endregion
public Title Copy()
{
return new Title
{
Level = Level,
Value = Value,
Children = Children.Select(c => c.Copy())
};
}
public bool IsLevelLowerThan(TitleLevel targetLevel)
{
return (int) Level <= (int) targetLevel;
}
}
internal enum TitleLevel
{
H1 = 1,
H2 = 2,
H3 = 3,
H4 = 4,
H5 = 5,
H6 = 6,
DummyValue = 0
}