使用CSV文件

时间:2017-04-16 22:40:44

标签: c# linq sorting csv

我已经工作并试图解决这个问题可能整整一个星期了,在这一点上我想知道我是否可以解决它而不会深入探讨C#语言,而且我是相当新的C#,以及使用CSV文件,排序和组织它们,所以我对这一切都缺乏经验。

我尝试按字母顺序对CSV文件进行排序,隐藏需要隐藏的项目,并让它们具有基于其父,子和孙元素的深度级别。

我已经成功完成了其中几个,编写了一些有用的代码,但我不知道如何按字母顺序对它们进行排序,并根据它们所属的父母和孩子给出适当的深度层到。

这是我尝试组织的模拟CSV:

ID;MenuName;ParentID;isHidden;LinkURL
1;Company;NULL;False;/company
2;About Us;1;False;/company/aboutus
3;Mission;1;False;/company/mission
4;Team;2;False;/company/aboutus/team
5;Client 2;10;False;/references/client2
6;Client 1;10;False;/references/client1
7;Client 4;10;True;/references/client4
8;Client 5;10;True;/references/client5
10;References;NULL;False;/references

我用分号分隔了这些项目,我已经显示了需要显示的项目,但是我没有像我应该那样对它们进行排序。

排序应如下所示:

Company
  About Us
    Team
  Mission
References
  Client 1
  Client 2

我试图通过获取斜杠的索引对它们进行排序或按顺序显示它们,但代码重现的不是它应该如何显示,并且看起来像这样:

Company
  About Us
  Mission
    Team
  Client 2
  Client 1
References

在另一个尝试中,我递归地将其父ID与id匹配,控制台显示如下所示:

Company
  About Us
  Mission
    Team
        Client 2
        Client 1
References

我已尝试与朋友解决此问题,即使他不知道如何解决此问题,因为此代码应该在使用不同父ID的不同文件上工作。

除此之外,我无法将它们索引到一个数组,因为只有索引为0或索引是基于它们的字母,或者如果我输入索引位置为1,则会使控制台崩溃。

这是第一部分的代码,我没有对它们进行排序:

class Program
{
    static void Main(string[] args)
    {
        StreamReader sr = new StreamReader(@"Navigation.csv");
        string data = sr.ReadLine();

        while (data != null)
        {
            string[] rows = data.Split(';');
            int id;
            int parentId;
            bool ids = Int32.TryParse(rows[0], out id);
            string name = rows[1];
            bool pIds = Int32.TryParse(rows[2], out parentId);
            string isHidden = rows[3];
            string linkUrl = rows[4];
            string[] splitted = linkUrl.Split('/');

            if (isHidden == "False")
            {
                List<CsvParentChild> pIdCid = new List<CsvParentChild>()
                {
                    new CsvParentChild(id, parentId, name, linkUrl)
                };
            }

            data = sr.ReadLine();
        }
    }
}

class CsvParentChild
{

    public int Id;
    public int ParentId;
    public string Name;
    public string LinkUrl;
    public List<CsvParentChild> Children = new List<CsvParentChild>();

    public CsvParentChild(int id, int parentId, string name, string linkUrl)
    {

        Id = id;
        ParentId = parentId;
        Name = name;
        LinkUrl = linkUrl;
        string[] splitted = linkUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

        if (splitted.Length == 1)
        {
            Console.WriteLine($". { name }");
        }
        else if (splitted.Length == 2)
        {
            Console.WriteLine($".... { name }");
        }
        else if (splitted.Length == 3)
        {
            Console.WriteLine($"....... { name }");
        }
    }
}

以下是第二部分:

class Program
{
    static void Main(string[] args)
    {
        // Get the path for the file
        const string filePath = @"../../Navigation.csv";

        // Read the file
        StreamReader sr = new StreamReader(File.OpenRead(filePath));
        string data = sr.ReadLine();

        while (data != null)
        {

            string[] rows = data.Split(';');

            ListItems lis = new ListItems();

            int id;
            int parentId;

            // Get the rows/columns from the Csv file
            bool ids = Int32.TryParse(rows[0], out id);
            string name = rows[1];
            bool parentIds = Int32.TryParse(rows[2], out parentId);
            string isHidden = rows[3];
            string linkUrl = rows[4];

            // Split the linkUrl so that we get the position of the
            // elements based on their slash
            string [] splitted = linkUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            // If item.isHidden == "False"
            // then display the all items whose state is set to false.
            // If the item.isHidden == "True", then display the item
            // whose state is set to true.
            if (isHidden == "False")
            {
                // Set the items
                ListItems.data = new List<ListItems>()
                {
                    new ListItems() { Id = id, Name = name, ParentId = parentId },
                };

                // Make a new instance of ListItems()
                ListItems listItems = new ListItems();

                // Loop through the CSV data
                for (var i = 0; i < data.Count(); i++)
                {
                    if (splitted.Length == 1)
                    {
                        listItems.ListThroughItems(i, i);
                    }
                    else if (splitted.Length == 2)
                    {
                        listItems.ListThroughItems(i, i);
                    }
                    else
                    {
                        listItems.ListThroughItems(i, i);
                    }
                }
            }

            // Break out of infinite loop
            data = sr.ReadLine();
        }
    }

public class ListItems
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int ParentId { get; set; }
        public static List<ListItems> data = null;
        public List<ListItems> Children = new List<ListItems>();

        // http://stackoverflow.com/a/36250045/7826856
        public void ListThroughItems(int id, int level)
        {
            Id = id;

            // Match the parent id with the id
            List<ListItems> children = data
                .Where(p => p.ParentId == id)
                .ToList();

            foreach (ListItems child in children)
            {
                string depth = new string('.', level * 4);
                Console.WriteLine($".{ depth } { child.Name }");
                ListThroughItems(child.Id, level + 1);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

对于每个项目,您需要构建一种&#34;排序数组&#34;由ids组成。排序数组由项目的祖先的id组成,从最远到最远的顺序。对于&#34; Team&#34;,我们的排序数组为[1, 2, 4]

以下是每个项目的排序数组:

[1]
[1, 2]
[1, 3]
[1, 2, 4]
[10, 5]
[10, 6]
[10, 7]
[10, 8]
[10]

一旦你有了这个,整理项目很简单。比较两个&#34;排序数组&#34;时,从每个数组中的数字开始。如果它们不同,请根据第一个数字的值进行排序,然后再完成。如果它们相同,请查看第二个数字。如果没有第二个数字,那么按数组的长度排序,即没有任何东西出现在某些东西之前。

应用此算法,我们得到:

[1]
[1, 2]
[1, 2, 4]
[1, 3]
[10]
[10, 5]
[10, 6]
[10, 7]
[10, 8]

之后,根据标志隐藏项目。我把它留给你,因为它很简单。深度很简单:它是排序数组的长度。

答案 1 :(得分:1)

我的应用程序已编译并使用您的数据生成以下输出:

Company
        About Us
                Team
        Mission
References
        Client 1
        Client 2
        Client 4
        Client 5

我会尝试使用对象关系来创建树状结构。 这个问题的主要困难是父母无所谓。孩子呢。 因此,在代码中的某个时刻,您将需要反转层次结构;首先解析孩子,但首先阅读他们的父母以创造输出。

我们树的根是没有父母的数据条目。

解析

这应该是非常自我解释的,我们有一个很好的类,它有一个构造函数来解析输入数组并将数据存储在它的属性中。 我们将所有行存储在列表中。在完成这个之后,我们几乎已经转换了列表,但根本没有进行排序。

public partial class csvRow
{
    // Your Data
    public int Id { get; private set; }
    public string MenuName { get; private set; }
    public int? ParentId { get; private set; }
    public bool isHidden { get; private set; }
    public string LinkURL { get; private set; }

    public csvRow(string[] arr)
    {
        Id = Int32.Parse(arr[0]);
        MenuName = arr[1];
        //Parent Id can be null!
        ParentId = ToNullableInt(arr[2]);
        isHidden = bool.Parse(arr[3]);
        LinkURL = arr[4];
    }
    private static int? ToNullableInt(string s)
    {
        int i;
        if (int.TryParse(s, out i))
            return i;
        else
            return null;
    }
}
static void Main(string[] args)
{
    List<csvRow> unsortedRows = new List<csvRow>();
    // Read the file
    const string filePath = @"Navigation.csv";
    StreamReader sr = new StreamReader(File.OpenRead(filePath));
    string data = sr.ReadLine();
    //Read each line
    while (data != null)
    {
        var dataSplit = data.Split(';');   
        //We need to avoid parsing the first line. 
        if (dataSplit[0] != "ID" )
        {
            csvRow lis = new csvRow(dataSplit);
            unsortedRows.Add(lis);
        }
         // Break out of infinite loop
         data = sr.ReadLine();
      }
      sr.Dispose();

       //At this point we got our data in our List<csvRow> unsortedRows
       //It's parsed nicely. But we still need to sort it.
       //So let's get ourselves the root values. Those are the data entries that don't have a parent.
       //Please Note that the main method continues afterwards.

创建我们的Tree Strukture并对项目进行排序

我们首先定义Children和一个返回它们的公共ChildrenSorted属性。这实际上是我们正在做的事情,它很容易排序而不是递归地工作。

我们还需要一个添加孩子的功能。它几乎会过滤输入并找到row.parentId = this.ID。

的所有行

最后一个是定义输出的函数,允许我们将一些东西打印到控制台中。

public partial class csvRow
{
    private List<csvRow> children = new List<csvRow>();
    public List<csvRow> ChildrenSorted
    {
        get
        {
            // This is a quite neet way of sorting, isn't it?
            //Btw this is all the sorting we are doing, recursion for win!
            return children.OrderBy(row => row.MenuName).ToList();
        }
    }

    public void addChildrenFrom(List<csvRow> unsortedRows)
    {
        // Add's only rows where this is the parent.
        this.children.AddRange(unsortedRows.Where(
            //Avoid running into null errors
            row => row.ParentId.HasValue &&
            //Find actualy children
            row.ParentId == this.Id &&
            //Avoid adding a child twice. This shouldn't be a problem with your data,
            //but why not be careful?
            !this.children.Any(child => child.Id == row.Id)));  


        //And this is where the magic happens. We are doing this recursively.
        foreach (csvRow child in this.children)
        {
            child.addChildrenFrom(unsortedRows);
        }
    }

    //Depending on your use case this function should be replaced with something
    //that actually makes sense for your business logic, it's an example on
    //how to read from a recursiv structure.
    public List<string> FamilyTree
    {
        get
        {
            List<string> myFamily = new List<string>();
            myFamily.Add(this.MenuName);
            //Merges the Trees with itself as root.
            foreach (csvRow child in this.ChildrenSorted)
            {
                foreach (string familyMember in child.FamilyTree)
                {
                    //Adds a tab for all children, grandchildren etc.
                    myFamily.Add("\t" + familyMember);
                }
            }
            return myFamily;
        }
    }
}

向树中添加项目并访问它们

这是我的主要功能的第二部分,我们实际使用我们的数据(在sr.Dispose()之后;)

    var roots = unsortedRows.Where(row => row.ParentId.HasValue == false).
        OrderBy(root => root.MenuName).ToList();

    foreach (csvRow root in roots)
    {
        root.addChildrenFrom(unsortedRows);
    }

    foreach (csvRow root in roots)
    {
        foreach (string FamilyMember in root.FamilyTree)
        {
            Console.WriteLine(FamilyMember);
        }
    }
    Console.Read();
}

整个源代码(Visual Studio C#控制台应用程序)

您可以使用它来测试,玩游戏并了解有关递归结构的更多信息。

版权所有2017 Eldar Kersebaum

根据Apache许可证2.0版(“许可证”)获得许可;    除非符合许可,否则您不得使用此文件。    您可以在

获取许可证副本
 http://www.apache.org/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则软件    根据许可证分发的“按现状”分发,    不附带任何明示或暗示的保证或条件。    有关管理权限的特定语言,请参阅许可证    许可证下的限制。

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

namespace ConsoleApplication49
    {
    class Program
    {
        static void Main(string[] args)
        {
            List<csvRow> unsortedRows = new List<csvRow>();
            const string filePath = @"Navigation.csv";
            StreamReader sr = new StreamReader(File.OpenRead(filePath));
            string data = sr.ReadLine();
            while (data != null)
            {
                var dataSplit = data.Split(';');   
                //We need to avoid parsing the first line. 
                if (dataSplit[0] != "ID" )
                {
                    csvRow lis = new csvRow(dataSplit);
                    unsortedRows.Add(lis);
                }
                // Break out of infinite loop
                data = sr.ReadLine();
            }
            sr.Dispose();
            var roots = unsortedRows.Where(row => row.ParentId.HasValue == false).
                OrderBy(root => root.MenuName).ToList();

            foreach (csvRow root in roots)
            {
                root.addChildrenFrom(unsortedRows);
            }

            foreach (csvRow root in roots)
            {
                foreach (string FamilyMember in root.FamilyTree)
                {
                    Console.WriteLine(FamilyMember);
                }
            }
            Console.Read();
        }
    }
    public partial class csvRow
    {
        // Your Data
        public int Id { get; private set; }
        public string MenuName { get; private set; }
        public int? ParentId { get; private set; }
        public bool isHidden { get; private set; }
        public string LinkURL { get; private set; }

        public csvRow(string[] arr)
        {
            Id = Int32.Parse(arr[0]);
            MenuName = arr[1];
            ParentId = ToNullableInt(arr[2]);
            isHidden = bool.Parse(arr[3]);
            LinkURL = arr[4];
        }
        private static int? ToNullableInt(string s)
        {
            int i;
            if (int.TryParse(s, out i))
                return i;
            else
                return null;
        }
        private List<csvRow> children = new List<csvRow>();
        public List<csvRow> ChildrenSorted
        {
            get
            {
                return children.OrderBy(row => row.MenuName).ToList();
            }
        }
        public void addChildrenFrom(List<csvRow> unsortedRows)
        {
            this.children.AddRange(unsortedRows.Where(
                row => row.ParentId.HasValue &&
                row.ParentId == this.Id &&
                !this.children.Any(child => child.Id == row.Id)));
            foreach (csvRow child in this.children)
            {
                child.addChildrenFrom(unsortedRows);
            }
        }
        public List<string> FamilyTree
        {
            get
            {
                List<string> myFamily = new List<string>();
                myFamily.Add(this.MenuName);
                foreach (csvRow child in this.ChildrenSorted)
                {
                    foreach (string familyMember in child.FamilyTree)
                    {
                        myFamily.Add("\t" + familyMember);
                    }
                }
                return myFamily;
            }
        }
    }
}