C# 将平面阵列数据转换为层次结构
我希望将数据从平面列表转换为层次结构。如何以可读的方式实现这一点,但性能仍然可以接受?是否有任何.NET库可以利用。我认为这在某些术语中被认为是一个“方面”(在本例中是由行业定义的) 因此,序列化后的结果对象应如下所示:C# 将平面阵列数据转换为层次结构,c#,.net,data-structures,C#,.net,Data Structures,我希望将数据从平面列表转换为层次结构。如何以可读的方式实现这一点,但性能仍然可以接受?是否有任何.NET库可以利用。我认为这在某些术语中被认为是一个“方面”(在本例中是由行业定义的) 因此,序列化后的结果对象应如下所示: { IndustryName: "Industry", ChildIndustryNodes: [ { IndustryName: "Energy", ChildIndustryNodes: [
{
IndustryName: "Industry",
ChildIndustryNodes: [
{
IndustryName: "Energy",
ChildIndustryNodes: [
{
IndustryName: "Energy Equipment & Services",
ChildIndustryNodes: [
{ IndustryName: "Oil & Gas Drilling", Hits: 8 },
{ IndustryName: "Oil & Gas Equipment & Services", Hits: 4 }
]
},
{
IndustryName: "Oil & Gas",
ChildIndustryNodes: [
{ IndustryName: "Integrated Oil & Gas", Hits: 13 },
{ IndustryName: "Oil & Gas Exploration & Production", Hits: 5 },
{ IndustryName: "Oil & Gas Refining & Marketing & Transporation", Hits: 22 }
]
}
]
},
{
IndustryName: "Materials",
ChildIndustryNodes: [
{
IndustryName: "Chemicals",
ChildIndustryNodes: [
{ IndustryName: "Commodity Chemicals", Hits: 24 },
{ IndustryName: "Diversified Chemicals", Hits: 66 },
{ IndustryName: "Fertilizers & Agricultural Chemicals", Hits: 22 },
{ IndustryName: "Industrial Gases", Hits: 11 },
{ IndustryName: "Specialty Chemicals", Hits: 43 }
]
}
]
}
]
}
其中“点击率”是属于该组的公司数量
为了澄清,我需要将列表
转换为列表
而不是序列化列表
尝试以下方法:
private static IEnumerable<Industry> GetAllIndustries(Industry ind)
{
yield return ind;
foreach (var item in ind.ChildIndustries)
{
foreach (var inner in GetAllIndustries(item))
{
yield return inner;
}
}
}
private static IndustryNode[] GetChildIndustries(Industry i)
{
return i.ChildIndustries.Select(ii => new IndustryNode()
{
IndustryName = ii.IndustryName,
Hits = counts[ii],
ChildIndustryNodes = GetChildIndustries(ii)
}).ToArray();
}
private static Dictionary<Industry, int> counts;
static void Main(string[] args)
{
List<Company> companies = new List<Company>();
//...
var allIndustries = companies.SelectMany(c => GetAllIndustries(c.Industry)).ToList();
HashSet<Industry> distinctInd = new HashSet<Industry>(allIndustries);
counts = distinctInd.ToDictionary(e => e, e => allIndustries.Count(i => i == e));
var listTop = distinctInd.Where(i => i.ParentIndustry == null)
.Select(i => new IndustryNode()
{
ChildIndustryNodes = GetChildIndustries(i),
Hits = counts[i],
IndustryName = i.IndustryName
}
);
}
私有静态IEnumerable GetAllIndustries(行业索引)
{
收益率指数;
foreach(工业中的var项目)
{
foreach(GetAllIndustries内部var(项目))
{
内部收益率;
}
}
}
私有静态行业代码[]GetChildIndustries(行业一)
{
return i.ChildIndustries.Select(ii=>newindustrynode()
{
行业名称=ii.行业名称,
点击次数=计数[ii],
ChildIndustryNodes=GetChildIndustries(二)
}).ToArray();
}
私有静态字典计数;
静态void Main(字符串[]参数)
{
上市公司=新上市公司();
//...
var allIndustries=companys.SelectMany(c=>GetAllIndustries(c.Industry)).ToList();
HashSet-Differentind=新的HashSet(所有行业);
counts=distincond.ToDictionary(e=>e,e=>allIndustries.Count(i=>i==e));
var listTop=distincend.Where(i=>i.ParentIndustry==null)
.Select(i=>newindustrynode()
{
ChildIndustryNodes=GetChildIndustries(i),
点击次数=计数[i],
行业名称
}
);
}
未经测试您正在寻找序列化程序。MSFT有一个是VS的原生版本,但我喜欢免费的Newtonsofts。MSFT文档和示例是,Newtonsoft文档是
Newtonsoft是免费的、简单的、快速的。尝试使用json序列化程序来实现这一目的。我看你的数据结构还可以,这只是序列化的问题
var industryNodeInstance = LoadIndustryNodeInstance();
var json = new JavaScriptSerializer().Serialize(industryNodeInstance);
如果要在序列化程序之间进行选择,请参见以下内容:
LoadIndustryNodeInstance方法
- 生成
列表
- 转换
IndustryTree=List
- 实现树方法,例如遍历。试着看
- 以下是一些psuedo代码,可能会帮助您顺利完成任务。我创建了一个地图/字典索引,并用公司列表填充它。然后我们从索引中提取顶级节点。请注意,可能存在边缘情况(例如,最初可能需要部分填充此索引,因为您的任何公司似乎都没有引用顶级节点,因此必须以其他方式填充这些节点)
字典索引=新字典();
公开作废插入(公司)
{
if(索引ContainsKey(公司、行业、行业名称))
{
索引[公司.行业.行业名称].hits++;
}
其他的
{
IndustryNode节点=新的IndustryNode(IndustryName=company.Industry,Hits=1);
索引[node.IndustryName]=节点;
if(index.ContainsKey(company.Industry.ParentIndustry.IndustryName))
{
索引[company.Industry.ParentIndustry.IndustryName].ChildrenIndustries.Add(节点);
}
}
}
列表topLevelNodes=索引
.Where(kvp=>kvp.Item.ParentIndustry==null)
.ToList(kvp=>kvp.Item);
效率是什么意思?最具可读性和可维护性,还是性能最好?对不起,我没有说清楚。它需要有效率,但我愿意在可读性和可维护性之间做一些折衷,即使它最终会序列化。为什么需要性能?你的名单似乎很小。我真的不喜欢有人无缘无故地给我一个负号。如果你没有理由,不要投反对票。我没有投反对票,但答案没有帮助。我已经在使用JSON.NET进行序列化了,但我仍然需要将其放入正确的结构中。这在最初的帖子中并不清楚(正如一半的答案所证明的)。听起来你好像在找表演。对不起,我误解了你的问题。我仍然认为不解释原因就减去一是很糟糕的。问题是LoadIndustryNodeInstance()
中发生了什么。我有一个列表
而不是列表
如果某个行业的子公司不受公司影响,此解决方案将不考虑该行业的子公司。@AhmedKRAIEM True,这些必须先插入。感谢您的回答,如果这种方法取而代之的是一个行业,那么在哪里可以应用递归来处理儿童之子的问题呢?你能进一步解释吗?按照当前数据的呈现方式,递归不能立即使用。例如,您可以通过递归搜索树,但这与线性搜索没有什么不同,因为没有指定的搜索顺序。distrinctInd.Where(i=>i.ParentIndustry==null)
不匹配任何元素,因为公司从未引用任何顶级行业元素。我一直试图让它以其他方式工作,但仍然有很多困难。请尝试distincend.Where(I=>I.ChildIndustries==null | | I.ChildIndustries.Count==0)
private static IEnumerable<Industry> GetAllIndustries(Industry ind)
{
yield return ind;
foreach (var item in ind.ChildIndustries)
{
foreach (var inner in GetAllIndustries(item))
{
yield return inner;
}
}
}
private static IndustryNode[] GetChildIndustries(Industry i)
{
return i.ChildIndustries.Select(ii => new IndustryNode()
{
IndustryName = ii.IndustryName,
Hits = counts[ii],
ChildIndustryNodes = GetChildIndustries(ii)
}).ToArray();
}
private static Dictionary<Industry, int> counts;
static void Main(string[] args)
{
List<Company> companies = new List<Company>();
//...
var allIndustries = companies.SelectMany(c => GetAllIndustries(c.Industry)).ToList();
HashSet<Industry> distinctInd = new HashSet<Industry>(allIndustries);
counts = distinctInd.ToDictionary(e => e, e => allIndustries.Count(i => i == e));
var listTop = distinctInd.Where(i => i.ParentIndustry == null)
.Select(i => new IndustryNode()
{
ChildIndustryNodes = GetChildIndustries(i),
Hits = counts[i],
IndustryName = i.IndustryName
}
);
}
var industryNodeInstance = LoadIndustryNodeInstance();
var json = new JavaScriptSerializer().Serialize(industryNodeInstance);
Dictionary<String, IndustryNode> index = new Dictionary<String, IndustryNode>();
public void insert(Company company)
{
if(index.ContainsKey(company.Industry.IndustryName))
{
index[company.Industry.IndustryName].hits++;
}
else
{
IndustryNode node = new IndustryNode(IndustryName=company.Industry, Hits=1);
index[node.IndustryName] = node;
if(index.ContainsKey(company.Industry.ParentIndustry.IndustryName))
{
index[company.Industry.ParentIndustry.IndustryName].ChildrenIndustries.Add(node);
}
}
}
List<IndustryNode> topLevelNodes = index
.Where(kvp => kvp.Item.ParentIndustry == null)
.ToList(kvp => kvp.Item);