Mam listę ciągów zawierających liczby w porządku rosnącym. Liczby są sformatowane w ten sposób:

  • 02 (Główna grupa - pierwszy poziom)
  • 02.00 (poziom pierwszego poziomu.Second)
  • 02.00.00 (Level First.Second Level.

Dwie cyfry poziomu są statyczne. Dwie cyfry po pierwszym poziomie mogą być dowolną liczbą, a to samo dotyczy trzeciego poziomu. Jest hierarchicznie zorganizowany.

Jak mogę grupować te poziomy w grupach, zapętląc listę?

0
Motivizer 15 styczeń 2021, 23:02

2 odpowiedzi

Najlepsza odpowiedź

Zrobiłbym to tak:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.txt";
        static void Main(string[] args)
        {
            string[] lines = File.ReadAllLines(FILENAME);
            List<ParagraphTitles> titles = lines.Select(x => new ParagraphTitles(x)).ToList();

            List<ParagraphTitles> sortedTitles = titles.OrderBy(x => x).ToList();

            ParagraphTitles root = new ParagraphTitles();
            root.CreateTree(sortedTitles, 0);


        }
    }
    public class ParagraphTitles : IComparable<ParagraphTitles>
    {
        public int[] paragraphs { get; set; }
        public string sParagraphs { get; set; }
        public string text { get; set; }
        public List<ParagraphTitles> chapters { get; set; }

        public ParagraphTitles() { }
        public ParagraphTitles(string line)
        {
            int firstSpace = line.IndexOf(' ');
            sParagraphs = line.Substring(0, firstSpace);
            paragraphs = line.Substring(0, firstSpace).Trim().Split(new char[] { '.' }).Select(x => int.Parse(x)).ToArray();
            text = line.Substring(firstSpace + 1);
        }
        public int CompareTo(ParagraphTitles other)
        {
            int minSize = Math.Min(paragraphs.Length, other.paragraphs.Length);

            for (int i = 0; i < minSize; i++)
            {
                if (paragraphs[i] != other.paragraphs[i])
                {
                    return paragraphs[i].CompareTo(other.paragraphs[i]);
                }
            }

            return paragraphs.Length.CompareTo(other.paragraphs.Length);
        }
        public void CreateTree(List<ParagraphTitles> chapters, int level)
        {
            var groups = chapters.GroupBy(x => x.paragraphs[level]).ToList();

            foreach (var group in groups)
            {
                List<ParagraphTitles> orderedChapters = group.OrderBy(x => x.paragraphs.Length).ToList();
                if (this.chapters == null) this.chapters = new List<ParagraphTitles>();
                this.chapters.Add(orderedChapters.First());
                orderedChapters.First().CreateTree(orderedChapters.Skip(1).ToList(), level + 1);
            }
        }

    }
}

Oto próbka pliku

00 The municipality's board Service text
00.01 The municipality's board Keywords Keywords
00.03 International business and the EU Service text Keywords Keywords
00.05 Visits, representation, etc. Keywords Keywords
00.06 Administration of foundations, grants and foundations Legal references Service text Keywords Keywords
00.07 Management principles Legal references Service text Keywords Keywords
00.13 Communication and information services Service text Keywords Keywords
00.14 Citizen Service Keywords Keywords
00.15 Administrative organization Service text Keywords Keywords
00.16 Experimental and development work Service text Keywords Keywords
00.17 Municipal / cross-sectoral cooperation Service text Keywords Keywords
00.18 Task and structural changes in municipalities, overall activities Legal references Service text Keywords Keywords
00.20 History of the municipality / institution, weapons, etc. Keywords Keywords
00.20.00 History of the municipality / institution, weapons, etc. in general [B] Legal references Service text Keywords Keywords
00.20.05 Naming of institutions, schools, etc. [B] Service text Keywords Keywords
00.22 The municipal council, committees, etc. - the municipality's board Service text Keywords Keywords
00.24 Municipal associations, associations, etc. Keywords Keywords
00.30 Budget - the municipality's financial management Legal references Service text Keywords Keywords
00.32 Accounting - the municipality's financial management Legal references Service text Keywords Keywords
00.34 Loans and borrowing - the municipality's financial management Legal references Service text Keywords Keywords
00.36 Mortgage deeds, bonds and shares Keywords Keywords
01 Spatial planning and nature conservation Service text
01.00 Physical planning and nature protection Keywords Keywords
01.01 National Planning Directives, etc. and regional development planning Service text Keywords Keywords
01.02 Municipal planning and local planning Service text Keywords Keywords
01.03 Zoning and land zone administration Legal references Service text Keywords Keywords
01.04 Subdivision conditions and other cadastral conditions Keywords Keywords
01.05 Nature conservation Legal references Service text Keywords Keywords
01.06 Geographical information systems Keywords Keywords
01.07 Holiday home areas Keywords Keywords
01.09 Raw material extraction Service text Keywords Keywords
01.10 Building protection and building preservation Keywords Keywords
01.11 Urban renewal and urban development Legal references Keywords Keywords
01.12 Allotment garden areas Keywords Keywords
01.13 Operation of agricultural land Legal references Keywords Keywords
01.15 Land distribution Service text Keywords Keywords
01.16 Assessment of Impacts on the Environment (EIA) [deleted] Legal references Service text Keywords Keywords
01.24 Coastal protection Legal references Service text Keywords Keywords
02 Byggeri
02.00 Construction Legal references Service text Keywords Keywords
02.01 Land use for development Legal references Keywords Keywords
02.02 The height and distance conditions of the buildings Legal references Keywords Keywords
02.03 Interior design of buildings Legal references Service text Keywords Keywords
02.04 Constructive provisions Keywords Keywords
02.05 Fire conditions Legal references Service text Keywords Keywords
02.08 Installations etc. Legal references Keywords Keywords
02.25 Fire protection measures for chimneys and fireplaces Legal references Keywords Keywords
02.34 Building permit and notification of construction work Legal references Keywords Keywords
03 Boliger
03.00 Boliger Stikord Stikord
03.01 Benyttelse af boliger Lovhenvisninger Servicetekst Stikord Stikord
03.02 Almene boliger, nybyggeri og renovering Lovhenvisninger Servicetekst Stikord Stikord
03.03 Private andelsboliger Lovhenvisninger Servicetekst Stikord Stikord
03.08 Drift, tilsyn og støtte til selvejende ungdomsboliger Lovhenvisninger Stikord Stikord
03.09 Lejeforhold mv. i private boliger Lovhenvisninger Servicetekst Stikord Stikord
03.10 Drift af og tilsyn med almene boliger (ikke-økonomisk) Lovhenvisninger Servicetekst Stikord Stikord
03.11 Økonomisk tilsyn med almene boliger Lovhenvisninger Servicetekst Stikord Stikord
03.12 Almene boliger - tvister mellem lejer og udlejer Lovhenvisninger Servicetekst Stikord Stikord
03.14 Støttede private ungdomsboliger Lovhenvisninger Servicetekst Stikord Stikord
03.16 Energibesparende foranstaltninger i pensionisters boliger [udgår 2021] Servicetekst Stikord Stikord
03.17 Statstilskud til omstilling af ældre boliger til kraftvarme [udgår 2021] Servicetekst Stikord Stikord
03.18 Statstilskud til omstilling af elopvarmede bygninger [udgår 2021] Servicetekst Stikord Stikord
03.22 Friplejeboliger Servicetekst Stikord Stikord
03.25 Boligplacering af flygtninge Lovhenvisninger Servicetekst Stikord Stikord
03.30 Landsbyggefondens årlige ramme til boligsocial indsats Lovhenvisninger Stikord Stikord
0
jdweng 15 styczeń 2021, 22:59

Ponieważ muszę wiele nudy, wdrożyłem ci jedną możliwość rozwiązania takiego problemu:

Drzewo, które obsługuje dowolną liczbę głębokości / poziomów, w których każdy urlop może mieć dane.

Mogę tylko radzić sobie, abyś był zawsze rozwiązany i zapytać konkretne problemy w drodze do rozwiązania.

Przykładowe dane używane w poniższym kodzie źródłowym:

"02" (without quote)
"02.00.05" (without quote)
"02.00.00" (without quote)
"99.99.99" (without quote)
"00.00.00.01" (without quote)

Kod źródłowy jest oczywisty:

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace stackoverflow_65742844
{
    /// <summary>
    /// The structure "LevelNode{AnyContentHere}" represents a tree.
    /// <br/>
    /// <br/>Meaning of words:
    /// <br/>Levels = string of levels (2000005) separated by dots (20.00.00.05) :P
    /// <br/>Level = single level without dot that has been taken from Levels.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Entry point for console application.
        /// </summary>
        static void Main()
        {
            // Its purpose: decide in this example where an item gets inserted in implementation of sorted dictionary.
            var comparer = new LevelComparer();

            // Represents the root level (node).
            var rootLevelNode = new LevelNode<AnyContentHere>(comparer);
            // Temporary means in this context, that..
            LevelNode<AnyContentHere> tempLevelNode;

            // this assignment..
            tempLevelNode = rootLevelNode.GetNodeOrCreate("02");
            tempLevelNode.Value = new AnyContentHere();

            // and now by this one.. :)
            tempLevelNode = rootLevelNode.GetNodeOrCreate("02.00.05");
            tempLevelNode.Value = new AnyContentHere();

            // and now by this one..
            tempLevelNode = rootLevelNode.GetNodeOrCreate("02.00.00");
            tempLevelNode.Value = new AnyContentHere();

            // and now by this one..
            tempLevelNode = rootLevelNode.GetNodeOrCreate("99.99.99");
            tempLevelNode.Value = new AnyContentHere();

            // and now by this one.. :)
            tempLevelNode = rootLevelNode.GetNodeOrCreate("00.00.00.01");
            tempLevelNode.Value = new AnyContentHere();

            // Visualizes root level node and its children and their children and th..
            VisualizeLevelNodeAndChildrenRecursively(rootLevelNode);

            ;
        }

        public static void VisualizeLevelNodeAndChildrenRecursively(LevelNode<AnyContentHere> levelNode, int numberOfChild = 0, int indexOfNode = 0)
        {
            Console.WriteLine($"{new string('\0', numberOfChild * 2)}{indexOfNode}: Group {levelNode.Key ?? "<root>"} contains {levelNode.Nodes.Count} direct children");

            foreach (var levelNodeChild in levelNode.Nodes.Values)
            {
                indexOfNode++;
                VisualizeLevelNodeAndChildrenRecursively(levelNodeChild, numberOfChild: numberOfChild + 1, indexOfNode);
                indexOfNode--;
            }
        }
    }

    /// <summary>
    /// Just an abstraction. It represents the root, a node, a leave or in whatever view you want to call it. 
    /// <br/>It can contain a key, a comparer, (child) nodes and a value.
    /// </summary>
    /// <typeparam name="TDerived">Because we need type of THIS as return value of methods below we need to know the dervied type</typeparam>
    /// <typeparam name="TKey">The key type you want to use.</typeparam>
    /// <typeparam name="TValue">The value you want to store.</typeparam>
    public abstract class SpecializedNode<TDerived, TKey, TValue>
        where TDerived : class
        where TKey : notnull
    {
        [MaybeNull, AllowNull]
        public TKey Key { get; }
        public IComparer<TKey> Comparer { get; }
        public SortedDictionary<TKey, TDerived> Nodes { get; }
        [MaybeNull, AllowNull]
        public TValue Value { get; set; }

        public SpecializedNode([AllowNull] TKey key, IComparer<TKey> comparer)
        {
            Nodes = new SortedDictionary<TKey, TDerived>(comparer);
            Key = key;
            Comparer = comparer;
        }

        /// <summary>
        /// Gets exitsing node or creates it iteratively.
        /// </summary>
        public abstract TDerived GetNodeOrCreate(TKey key);
    }

    public class LevelNode<T> : SpecializedNode<LevelNode<T>, string, T>
    {
        protected LevelNode(string key, IComparer<string> comparer)
            : base(key, comparer) { }

        public LevelNode(IComparer<string> comparer)
            : base(default(string), comparer) { }

        /// <summary>
        /// Gets existing node or creates it.
        /// </summary>
        /// <param name="level"></param>
        /// <returns></returns>
        protected LevelNode<T> getNodeOrCreate(string level)
        {
            LevelNode<T> levelNode;

            if (!Nodes.TryGetValue(level, out levelNode!))
            {
                levelNode = new LevelNode<T>(level, Comparer);
                Nodes.Add(level, levelNode);
            }

            return levelNode;
        }

        /// <summary>
        /// Gets exitsing node or creates it iteratively.
        /// </summary>
        /// <param name="levels">String of levels (2000005) separated by dots (20.00.00.05).</param>
        /// <returns>Node of latest level in <paramref name="levels"/>.</returns>
        public override LevelNode<T> GetNodeOrCreate(string levels)
        {
            if (levels == null)
            {
                return this;
            }

            // Because we don't like recursion we want to work iteratively.
            // We begin by assigning start node..
            LevelNode<T>? levelNode = this;
            // start dot index..
            var dotIndex = levels.IndexOf('.');
            // and the to be shortened levels.
            var toBeShortendLevels = levels;

            /// While a dot from left to right has been found in <see cref="toBeShortendLevels"/>,
            /// search for next level node child.
            while (dotIndex != -1)
            {
                // We know next dot, so we cut out everything before dot.
                // This will be our level (see top what "level" means).
                var level = toBeShortendLevels.Substring(0, dotIndex);
                // ITERATIVE:  Now let's get child node.
                levelNode = levelNode.getNodeOrCreate(level);
                // ITERATIVE: Now we cut out everything after the dot and the dot itself.
                toBeShortendLevels = toBeShortendLevels.Substring(dotIndex + 1);
                // ITERATIVE: Let's check for next dot index.
                dotIndex = toBeShortendLevels.IndexOf('.');
            }

            // When the while loop finished we haven't yet the last level node but the node before that.
            // This gets us the last node we want.
            levelNode = levelNode.getNodeOrCreate(toBeShortendLevels);
            return levelNode;
        }
    }

    /// <summary>
    /// This comparer wraps <see cref="Comparer{string}.Default"/> internally.
    /// We can do so, because <see cref="string"/> is a value type and for value
    /// types <see cref="Comparer{T}"/> has been already implemented and is usable
    /// through <see cref="Comparer{T}.Default"/>.
    /// This comparer relies on the fact that comparing level x and y are going
    /// to have SAME length (left filled zeroes).

    /// </summary>
    public class LevelComparer : IComparer<string>
    {
        private Comparer<string> comparer;

        public LevelComparer() =>
            comparer = Comparer<string>.Default;

        /// <summary>
        /// If x greater than y then return 1, if x equals y then return 0 but if x smaller y then return -1.
        /// 
        /// x = 01, y == 00
        /// x = 20, y == 02
        /// ...
        /// => 1
        /// 
        /// x = 02, y == 02
        /// ...
        /// => 0
        /// 
        /// x = 00, y = 05
        /// ...
        /// => -1
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public int Compare([AllowNull] string x, [AllowNull] string y) =>
            comparer.Compare(x, y);
    }

    // Can declare a string inside this class or you remove this and 
    // replace "AnyContentHere" with data type "string" for example.
    public class AnyContentHere { }
}

Wyjście konsoli to:

0: Group <root> contains 3 direct children
  1: Group 00 contains 1 direct children
    2: Group 00 contains 1 direct children
      3: Group 00 contains 1 direct children
        4: Group 01 contains 0 direct children
  1: Group 02 contains 1 direct children
    2: Group 00 contains 2 direct children
      3: Group 00 contains 0 direct children
      3: Group 05 contains 0 direct children
  1: Group 99 contains 1 direct children
    2: Group 99 contains 1 direct children
      3: Group 99 contains 0 direct children

Mogę tylko doradzić, aby skopiować kod i wkleić go w nowo utworzonym projekcie konsoli i ustawić punkty przerwania, jeśli nie rozumiesz, jak działa kod.

I oczywiście nie biorę cię z pracy, aby przeczytać dane w implementowanym sposobie i oddzielnym poziomie (klucz) i dane (zdanie). Mogę doradzić HTMLAGilityPack przeanalizować HTML, jeśli tak potrzebujesz.

0
Teroneko 16 styczeń 2021, 00:59