将数据从扁平数组转换为分层结构

3

我希望将一个平面列表转换为分层结构。有没有一种既易于阅读又具有良好性能的方法来实现这一目标?是否有任何可以利用的.NET库?在某些行业术语中,我认为这被称为“facet”。

public class Company
{        
    public int CompanyId { get; set; }
    public string CompanyName { get; set; }
    public Industry Industry { get; set; }
}

public class Industry
{
    public int IndustryId { get; set; }
    public string IndustryName { get; set; }
    public int? ParentIndustryId { get; set; }
    public Industry ParentIndustry { get; set; }
    public ICollection<Industry> ChildIndustries { get; set; }
}

现在假设我有一个List<Company>,我想将其转换为List<IndustryNode>

//Hierarchical data structure
public class IndustryNode
{
    public string IndustryName{ get; set; }
    public double Hits { get; set; }
    public IndustryNode[] ChildIndustryNodes{ get; set; }
}

因此,在序列化后,生成的对象应该像以下这样看起来:
{
    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 }
                    ]
                }
            ]
        }
    ]
}

“Hits”是指落入该组的公司数量。

为了澄清,我需要将一个List<Company>转换成一个List<IndustryNode>而不是序列化一个List<IndustryNode>


“效率”是什么意思?最易读和可维护的代码还是最高效的代码? - CookieOfFortune
抱歉我没有表达清楚。它需要高效,但我愿意在可读性和可维护性方面做出一些权衡。 - parliament
最终它将被序列化。 - parliament
为什么需要性能?你的列表似乎很小。 - CookieOfFortune
4个回答

1

试试这个:

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

未测试

distrinctInd.Where(i => i.ParentIndustry == null)没有匹配任何元素,因为公司从未引用任何顶级行业元素。我一直在尝试使其以其他方式工作,但仍然遇到了很多困难。 - parliament
尝试使用 distinctInd.Where(i => i.ChildIndustries == null || i.ChildIndustries.Count == 0) - Ahmed KRAIEM

0
尝试使用JSON序列化器来实现此目的。我看到你的数据结构是正确的,这只是一个序列化的问题。
var industryNodeInstance = LoadIndustryNodeInstance();

var json = new JavaScriptSerializer().Serialize(industryNodeInstance);

如果您想在序列化程序之间进行选择,请查看: http://www.servicestack.net/benchmarks/#burningmonk-benchmarks

LoadIndustryNodeInstance 方法

  • 构建 List<Industry>

  • 转换 IndustryTree = List<IndustryNode>

  • 实现树方法,如遍历。尝试查看 C# 中的树数据结构


问题涉及到LoadIndustryNodeInstance()中会发生什么。我有一个List<Company>而不是List<IndustryNode> - parliament

0

这里有一些伪代码,可能会帮助你走上正轨。我创建了一个映射/字典索引,并用公司列表填充它。然后我们从索引中提取顶级节点。请注意,可能会出现边缘情况(例如,此索引可能需要最初部分填充,因为似乎您的公司从未引用过最顶层的节点,因此必须以其他方式填充这些节点)。

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

如果未将行业的子级分配给公司,则此解决方案将不考虑行业的子级。 - Ahmed KRAIEM
@AhmedKRAIEM 是的,这些必须最初被插入。 - CookieOfFortune
谢谢你的回答。如果这个方法接受一个行业作为参数,那么递归应该如何应用来处理子孙级别的情况呢? - parliament
你能进一步解释吗?目前数据的呈现方式,递归并不能立即使用。例如,你可以通过递归搜索树,但这与线性搜索没有区别,因为没有规定的搜索顺序。 - CookieOfFortune

0
你正在寻找一个序列化器。微软有一个原生于VS的,但我喜欢免费的Newtonsoft。微软的文档和示例在这里,Newtonsoft的文档在这里
Newtonsoft是免费、易用且更快的。

我真的不喜欢被人无缘无故地给我一个负一评价。如果你没有理由,请不要把它投下去。 - CodeChops
我没有给回答投反对票,但它并不有用。我已经将使用JSON.NET进行序列化,但我仍然需要将其放入适当的结构中。 - parliament
在原始帖子中并不清楚(正如一半的回答所证明的那样)。听起来你是在寻找性能。抱歉我误解了你的问题。我仍然认为减去任何东西而不解释原因是很糟糕的。 - CodeChops

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接