Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Working with CSV file

Tags:

c#

sorting

csv

linq

I've been working and trying to solve this problem for maybe a whole week, which at this point I am wondering if I can solve it without it diving even deeper into the C# language, and I'm quite fairly new to C#, as well as working with CSV files and sorting and organizing them, so I'm fairly inexperienced into the whole spectrum of this.

I'm trying to sort a CSV file alphabetically, hide items that need to be hidden and have them have depth levels based on their parents, child and grandchild elements.

I've been successful with a couple of them, and written somewhat working code, but I don't know how to sort them alphabetically and give them the proper depth layer based on the parent and child they belong to.

Here's the mockup CSV that I've been trying to organize:

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

I've delimited the items by the semicolon, I've displayed the items that needs to be shown, but I fail to sort them like I should.

The sorting should look like this:

Company
  About Us
    Team
  Mission
References
  Client 1
  Client 2

I've tried to sort them or display them in that order by getting the index of the slash, but what the code reproduces is not how it should be displayed, and, it looks like this:

Company
  About Us
  Mission
    Team
  Client 2
  Client 1
References

In the other try, where I recursively match their parent id with the id, the console display looks like this:

Company
  About Us
  Mission
    Team
        Client 2
        Client 1
References

I've tried solving this with a friend, and, even he doesn't know how to approach this problem, since this code should work on a different file that uses different parent ids.

On top of all this, I am unable to index them to an array, because there's only index of 0 or the index is based on their letters or crashes the console if I enter the index position of 1.

Here's the code for the first part where I fail to sort them:

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

And here's for the second part:

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);
            }
        }
    }
}
like image 705
Timathy Avatar asked Jul 30 '26 06:07

Timathy


1 Answers

For each item, you need to construct a kind of "sort array" consisting of ids. The sort array consists of the ids of the item's ancestors in order from most distant to least distant. For "Team", our sort array is [1, 2, 4].

Here are the sort arrays of each item:

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

Once you have this, sorting the items is simple. When comparing two "sort arrays", start with the numbers in order in each array. If they are different, sort according to the value of the first number and you're done. If they are the same, look at the second number. If there is no second number, then sort by the length of the arrays, i.e., nothing comes before something.

Applying this algorithm, we get:

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

After that, hide the items based on the flag. I leave that to you because it's so simple. Depth is easy: It's the length of the sort array.

like image 70
Gregory Higley Avatar answered Jul 31 '26 19:07

Gregory Higley



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!