Рекурсивный список в красиво отформатированную таблицу - PullRequest
0 голосов
/ 17 мая 2018

Я столкнулся с несколько сложной проблемой, которую мне трудно обернуть вокруг.

У меня есть класс:

 public class Location
 {
    public string Name { get; set; }

    public List<Location> ChildLocations { get; set; }
 }

Он снова имеет ссылку на дочерние объекты Location. Так что это рекурсивный список, и я хочу вывести этот список в красиво отформатированную таблицу HTML. Это код:

using System.Collections.Generic;
using System.Web.Mvc;

namespace WebApplication1.Controllers
{
    public class Location
    {
        public string Name { get; set; }

        public List<Location> ChildLocations { get; set; }
    }

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            List<Location> locations = new List<Location>() {
                 new Location() {
                    Name = "Item 1",
                    ChildLocations = new List<Location>() {
                        new Location()
                        {
                            Name="Female",
                            ChildLocations = new List<Location>()
                            {
                                new Location() { Name = "Female 1" },
                                new Location() { Name = "Female 2" }
                            }

                        },
                        new Location()
                        {
                            Name="Male",
                            ChildLocations = new List<Location>()
                            {
                                new Location() { Name = "Male 1" },
                                new Location() { Name = "Male 2" }
                            }

                        }
                    }
                },
                 new Location() {
                    Name = "Item 2",
                    ChildLocations = new List<Location>() {
                        new Location()
                        {
                            Name="Female",
                            ChildLocations = new List<Location>()
                            {
                                new Location() { Name = "M1" },
                                new Location() { Name = "M2" },
                                new Location() { Name = "M3" }
                            }

                        },
                        new Location()
                        {
                            Name="Male",
                            ChildLocations = new List<Location>()                            

                        },
                        new Location()
                        {
                            Name="Unknown",
                            ChildLocations = new List<Location>()

                        }
                    }
                }
            };

            return View(locations);
        }
    }
}

и я хочу, чтобы вывод выглядел примерно так:

enter image description here

<table class="table table-border">
  <tr>
    <td rowspan="4">
      Item 1
    </td>
    <td rowspan="2">
      Female
    </td>   
    <td>
      Female 1
    </td>
  </tr> 
  <tr>
    <td>Female 2</td>
  </tr>
  <tr>
    <td rowspan="2">Male</td>
    <td>Male 1</td>
  </tr>
  <tr>
      <td>Male 2</td>    
  </tr>
  <tr>
    <td rowspan="5">
      Item 2      
    </td>
    <td rowspan="3">Female</td>
    <td>M1</td>
  </tr>
  <tr>
    <td>M2</td>
  </tr>
  <tr>
    <td>
      M3
    </td>
  </tr>
  <tr>
    <td>Male</td>
  </tr>
  <tr>
    <td>Unknown</td>
  </tr>
</table>

и если кто-то хочет просмотреть HTML, у меня есть jsfiddle для него:

https://jsfiddle.net/4pk0necp/

Я хочу визуализировать таблицу такого типа, используя данные, которые у меня есть в моей программе cshtml:

@using WebApplication1.Controllers;
@model List<Location>
@{
    ViewBag.Title = "Home Page";
}

Я понимаю, что потребуется функция для вычисления диапазона строк, поэтому я создал эту крошечную функцию, которая правильно возвращает глубину:

public static int GetDepth(this Location location)
    {
        int noOfchildren = 0;
        bool counted = false;
        foreach (Location item in location.ChildLocations)
        {
            if (item.ChildLocations.Count <= 0)
            {
                if (!counted)
                {
                    noOfchildren += location.ChildLocations.Where(i => i.ChildLocations.Count <= 0).Count();
                    counted = true;
                }
            }
            else
                noOfchildren += GetDepth(item);
        }

        return noOfchildren;
    }

Список деревьев, о которых идет речь, является лишь примером, и в дереве может быть много уровней глубины. Любая помощь приветствуется.

Редактировать: Я настроил свою функцию GetDepth, так как нам нужно только количество конечных узлов.

1 Ответ

0 голосов
/ 17 мая 2018

Попробуйте использовать следующий класс.Только едва проверено:

public class TreeDrawer {

    private readonly Dictionary<Location, int> _depthMap;

    public TreeDrawer() {
        _depthMap = new Dictionary<Location, int>();
    }

    public string Draw(IEnumerable<Location> locations) {
        var sb = new StringBuilder("<table>");

        bool first = true;
        foreach (var l in locations) {
            Draw(l, sb, true, first);
            first = false;
        }

        sb.Append("</table>");

        return sb.ToString();
    }

    private void Draw(Location l, StringBuilder sb, bool fromRoot, bool first) {
        int depth = GetDepth(l);
        bool openedRow = false;
        if (fromRoot || !first) {
            sb.Append("<tr>");
            openedRow = true;
        }
        sb.Append("<td");
        if (depth > 1) {
            sb.Append(" rowspan=\"");
            sb.Append(depth);
            sb.Append("\"");
        }
        sb.Append(">");
        sb.Append(l.Name);
        sb.Append("</td>");

        bool isFirstChild = true;
        if (l.ChildLocations != null) {
            foreach (var child in l.ChildLocations) {
                Draw(child, sb, false, isFirstChild);
                isFirstChild = false;
            }
        }
        if (openedRow) {
            sb.Append("</tr>");
        }

    }

    private int GetDepth(Location l) {
        if (!_depthMap.ContainsKey(l)) {
            _depthMap.Add(l, Math.Max(1, l.ChildLocations?.Sum(GetDepth) ?? 0));
        }
        return _depthMap[l];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...