0

Is there a way to find empty lines insinde of a matrix and insert values inside these empty space? I have a method that allows me to insert and erase values inside these matrix however when I erase something by id (the entire line) it creates an empty line and the insertion is always on the next line. What I need is method to search for empty space inside the matrix and to reajust this matrix. Here's the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace menu
{
    class Program
    {
        private static int id = 1;
        enum dataInsert { Id, Name, surname, address };

        static void Main(string[] args)
        {
            string[,] matrix = new string[10, 4];

            do { insertStudent(matrix);
                Console.WriteLine();
                insertStudent(matrix);
                deleteByid(matrix);
                listStudent(matrix);

            } while (true);
        }


        static int generateId()
        {
            return id++;
        }
        static void insertStudent(string[,] matrix)
        {
            int n = generateId();

            for (int j = 1; j < matrix.GetLength(1); j++)
            {
                matrix[n - 1, 0] = Convert.ToString(n);
                do
                {
                    Console.Write($"Insert {Enum.GetName(typeof(dataInsert), j)}: ");
                    matrix[n - 1, j] = Console.ReadLine();
                } while (String.IsNullOrEmpty(matrix[n - 1, j]));
            }
        }
        static int searchId(string[,] matrix)
        {
            int choosenId, index = -1;

            do
            {
                Console.Write("Insert ID: ");

            } while (!int.TryParse(Console.ReadLine(), out choosenId));


            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                if (Convert.ToString(choosenId) == matrix[i, 0])
                {
                    index = i;
                }
            }

            return index;
        }


        static void deleteByid(string[,] matrix)
        {
            int pos = searchId(matrix);
            if (pos != -1)
            {
                for (int i = pos; i < pos + 1; i++)
                {
                    for (int j = 0; j < matrix.GetLength(1); j++)
                    {
                        matrix[i, j] = null;
                    }
                }
            }
            else { Console.WriteLine("ID does not exist"); }
        }

        static void listStudent(string[,] matrix)
        {

            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    Console.Write($"[{i}],[{j}]: {matrix[i, j]}\t");
                }

                Console.WriteLine("\n\t");

            }
        }
    }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Ricardo
  • 87
  • 1
  • 2
  • 9
  • the code on main allows me to insert values twice in arrow, then I erase ID 1, and the final list shows first line of the matriz empty and the second line with values on it. What I need is reajust these values so the output does not have these "holes". – Ricardo Aug 05 '18 at 08:59
  • 2
    Is there a reason why you've chosen to use a 2D array for storing this information in the first place? If it's only because *that's what your output needs to look like*, realise that designing your data structures around your display is rarely the right way to approach a problem. It looks like you *should* have a `List` where `Student` is a class with named properties such as `Id`. – Damien_The_Unbeliever Aug 05 '18 at 09:05
  • (or possible a `Dictionary` if you want fast lookup by `Id` also) – Damien_The_Unbeliever Aug 05 '18 at 09:07

2 Answers2

0

There is no built-in way in C# to change the size 2D array, which is what you would need to do ultimately. If you want remove, then use one of the collection classes such as System.Collections.Generic.List<>.

If you want to stick with the array then you'll need to create a new one and copy across each remove (basically copy all rows except the one being removed).

A crude re-implementation of your method deleteByid for as you have said you are keen to stick with an array. It could probably be improved but ultimately your 2D array isn't really the best way to approach this.

static void deleteByid(ref string[,] matrix)
{
    int pos = searchId(matrix);
    int newRowCount = 0;

    if (pos != -1)
    {
        var newArray = new string[matrix.GetLength(0) - 1, matrix.GetLength(1)];
        for (int n = 0; n < matrix.GetLength(0) - 1; n++)
        {
            if (pos != n)
            {
                for (int i = 0; i < matrix.GetLength(1) - 1; i++)
                {
                    newArray[newRowCount, i] = matrix[n, i];
                } 
                newRowCount++;
            }
        } 
        matrix = newArray;
    }
    else { Console.WriteLine("ID does not exist"); }
}

This copies to a new 2D array, skipping the row being deleted, then re-points the reference for your original array.

Note I changed the argument to ref to allow us to initialise to a different array, so you will need to change the call to:

deleteByid(ref matrix);

This will work but throw an exception when it loops round to insertStudent(matrix) again. This is because of the way you are incrementing an id variable to know what to do with a new one. However, you use it to decide on indexing in insertStudent(). If you're keen also to keep that might I suggest you decrement that value in deleteStudent().

Ben Hall
  • 1,353
  • 10
  • 19
  • I want to stick with that array, if I was going to copy across another array the problem is the Id is created acording the index position, Isn't somehow I can scrive for null values and reajust the lines of the array? – Ricardo Aug 05 '18 at 09:27
  • Okay have re-written your delete method see answer update. – Ben Hall Aug 05 '18 at 09:59
  • I thought it wasn't necessary to use ref on a matrix or arrays while programming in C#, at leat I heard that before, anyway. I'm not sure if I got the exeception, you mean to decrement the id, while make the insertion? If it's Id which should decremented , it can't be done because it is meant to be an auto increment Id. – Ricardo Aug 05 '18 at 10:16
  • To change values yes. To reassign to null or new array it needs to be explicit with `ref`. To see the method I have written for you working just remove the `do` loop you have in `main`. I think that covers this question? Your issue with the `id` variable is something else really. The problem with that is you use it to decide where to insert new items but if you have removed an item your array has just shrunk. Just a new design choice for you to think about really. – Ben Hall Aug 05 '18 at 10:23
  • if you're interested there is a clear explanation of why it needs to be ref towards the end of this answer: https://stackoverflow.com/questions/10325323/passing-arrays-by-value-and-by-reference – Ben Hall Aug 05 '18 at 10:26
  • ok, thank you very much. I don't know how to design in different way, i'll have to think about it and decide which way to go – Ricardo Aug 05 '18 at 10:48
  • Sorry Ricardo I have completely misread your question. Will change my answer as soon as possible. – Ben Hall Aug 05 '18 at 11:04
  • it works without the do while, the problem is I need it on a do while – Ricardo Aug 05 '18 at 11:05
  • I have left this answer here was it is valid for an approach of removing rows completely on delete. – Ben Hall Aug 05 '18 at 12:27
0

You would be better off using one of the collection classes such as System.Collections.Generic.List<> with a class of your own as mentione din comments. If you want to stick with the array here is a re-write of insertStudent with a new method getInsertIndex which will do the job for you.

All I'm doing in getInsertIndex is finding the first available row that has a null in position 0 (you will have set this to null when you doid the delete), and returning its index. Else -1 (you'll need to think about how you will extend you program to grow array if there is no space).

static int getInsertIndex(string[,] matrix)
{
    for (int j = 0; j < matrix.GetLength(0) - 1; j++)
    {
        if (string.IsNullOrEmpty(matrix[j, 0])) return j;
    }

    return -1;
}

Just a few changes to the logic in insertStudent to use the new method:

static void insertStudent(string[,] matrix)
{
    int id = generateId();
    int n = getInsertIndex(matrix);

    matrix[n, 0] = Convert.ToString(id);

    for (int j = 1; j < matrix.GetLength(1); j++)
    {
        do
        {
            Console.Write($"Insert {Enum.GetName(typeof(dataInsert), j)}: ");
            matrix[n, j] = Console.ReadLine();
        } while (String.IsNullOrEmpty(matrix[n, j]));
    }
}

We still generate the new ID but now we also find the first available free space. We then set the first element of that row to the new id and then enter your original loop (adapted slightly) to populate with input as before.

Ben Hall
  • 1,353
  • 10
  • 19
  • I've gone with a brand new answer @Ricardo as I completely misread your question the first time. – Ben Hall Aug 05 '18 at 11:20
  • I got that method that you created , bassicaly it scrives for a position and then does the insert, without messing the id. Means that now the program is available to perform without empty lines from the delete method, you really really helped me! – Ricardo Aug 05 '18 at 12:47