2

I don't know how to create a 2 dimensional array using 5 columns and n rows where n = characters in the string/5 with this value being rounded up using Math.Ceiling. The characters in the string is arranged horizontally left to right, top to bottom in the 2 dimensional array.

For example if the entered string is "DELICIOUS FOOD " the 2D array should be:

D E L I C
I O U S 
F O O D X

In this case the space also counts as a character. Left over spaces in the array should be marked with the character 'X'.

I have been running into syntax issues with rounding the string/5 using math ceiling and also confused about how to create a 2D array along with populating it with the characters in the original string.

internal class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine("Enter Customer name: ");
        string customer = Console.ReadLine();
        double customerLength = customer.Length;
        double nRows = Math.Ceiling(customer.Length / 5);

        char[,] table = new char[Convert.ToInt32(nRows)][5];
    }
}
pfx
  • 20,323
  • 43
  • 37
  • 57
  • 2
    Is there supposed to be an extra space at the end of the `"DELICIOUS FOOD "` string? If so, why is there an "X" at the end of your expected result array, given that spaces count as a character? – Matthew Watson Apr 07 '23 at 08:54

4 Answers4

0

There are few things you need to research about before finding a solution to this.

  1. How to declare a 2D array in c#
  2. Integer division vs floating point division in C#

If you have understood these concepts, you can come up with an error free solution.

// Displays the prompt "Enter Customer name:" in the console window
Console.WriteLine("Enter Customer name: ");

// Reads a string input from the user through the console and assigns it to the variable "customer"
var customer = Console.ReadLine();

// Starts an "if" statement to check if the "customer" variable is not null.
if (customer != null)
{
    // Calculates the number of rows needed to display the customer name
    var n = (customer.Length / 5.0);
    // Rounds up the number of rows to the nearest integer value
    var nRows = Math.Ceiling(n);
    // Creates a 2D char array with the calculated number of rows and 5 columns
    var table = new char[Convert.ToInt32(nRows), 5];
    // Initializes the index variable to 0
    var index = 0;

    // Iterates through each row of the "table" array
    for (var row = 0; row < table.GetLength(0); row++)
    {
        // Iterates through each column of the "table" array
        for (var column = 0; column < table.GetLength(1); column++)
        {
            // Assigns the character value of "customer[index]" to the "table" array if "index" is within the range of the "customer" string, otherwise assigns 'X'
            table[row, column] = customer.Length <= index ? 'X' : customer[index];
            // Writes the character value to the console followed by a space
            Console.Write($"{table[row, column]} ");
            // Increments the index variable
            index++;
        }
        // Writes a newline character to the console to start a new row
        Console.WriteLine();
    }
}
Nishan
  • 3,644
  • 1
  • 32
  • 41
0

Let's extract the method for your task. We are given value and colCount and we want char[,] as a result.

  1. First we should allocate the char[,] array: we want value.Length / colCount rows plus extra row if value.Length doesn't divide evenly.
  2. The we should place character after character into the array: row is index / colCount when column is index % colCount.

Code:

private static char[,] ToTable(string value, int colCount) {
  if (value is null)
    throw new ArgumentNullException(nameof(value));

  if (colCount <= 0)
    throw new ArgumentOutOfRangeException(nameof(colCount));

  char[,] result = new char[
    value.Length / colCount + (value.Length % colCount == 0 ? 0 : 1), 
    colCount];

  // Fill the array with `X`:
  for (int r = 0; r < result.GetLength(0); ++r) 
    for (int c = 0; c < result.GetLength(1); ++c)   
      result[r, c] = 'X';

  for (int i = 0; i < value.Length; ++i)
    result[i / result.GetLength(1), i % result.GetLength(1)] = value[i];

  return result;
}

Fiddle

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
0

Firstly, how to calculate the required number of rows for a string of length n using cols columns:

rows = (n + cols - 1) / cols

This uses integer division for the calculation to avoid having to use floating point.

In order to fill the array, it would be nice to treat it as a 1D array so we can just copy the text into it. Because 2D arrays are stored as row-major order, this would work just fine.

We can do this by creating a Span<char> for the 2D array using a helper method such as this (lifted from here):

public static Span<T> AsSpan<T>(Array array)
{
    return MemoryMarshal.CreateSpan(
        ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)),
        array.Length);
}

Putting those together we get the following:

string text = "DELICIOUS FOOD";

int cols  = 5;
int rows  = (text.Length + cols - 1) / cols;
var array = new char[rows, cols];
var span  = AsSpan<char>(array); // Create a span that encompasses all the elements of 'array' as a single span.

text.CopyTo(span);                 // Copy the text to the span; this will wrap at the correct places.
span.Slice(text.Length).Fill('X'); // Fill the remainder of the span with 'X'.

Note that span.Slice(text.Length) returns a new span starting at an offset of text.Length elements - which is where we need to start filling with 'X' characters for the remainder of the last row.

Also note that Span<T>.Fill(item) just fills that span with the specified item.

Putting this together into a test console app (try it online):

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Console1;

public static class Program
{
    public static void Main()
    {
        string text = "DELICIOUS FOOD";

        int cols  = 5;
        int rows  = (text.Length + cols - 1) / cols;
        var array = new char[rows, cols];
        var span  = AsSpan<char>(array); // Create a span that encompasses all the elements of 'array' as a single span.

        text.CopyTo(span);                 // Copy the text to the span; this will wrap at the correct places.
        span.Slice(text.Length).Fill('X'); // Fill the remainder of the span with 'X'.

        // Print the result.

        for (int r = 0; r < rows; ++r)
        {
            for (int c = 0; c < cols; ++c)
            {
                Console.Write(array[r, c]);
            }

            Console.WriteLine();
        }
    }

    public static Span<T> AsSpan<T>(Array array)
    {
        return MemoryMarshal.CreateSpan(
            ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)),
            array.Length);
    }
}

This outputs:

DELIC
IOUS
FOODX
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

If you're using .NET 6 (or later), you can use the new LINQ Chunk method:

string s = "DELICIOUS FOOD";
int batchSize = 5;
int len = s.Length;
int nBatches = (int)Math.Ceiling((double)len / batchSize);
var parts = s.PadRight(batchSize * nBatches, 'X').Chunk(batchSize).ToArray();

foreach(var part in parts)
{
    Console.WriteLine(string.Join(" ", part));
}

Outputs:

D E L I C
I O U S
F O O D X
Andrew Morton
  • 24,203
  • 9
  • 60
  • 84