Home > Net >  How to convert a C# list to a string with a fixed number of items per line using StringBuilder?
How to convert a C# list to a string with a fixed number of items per line using StringBuilder?

Time:02-20

I am trying to convert a List<int> of several hundred integers to a string that, when printed, has a specified number of integers per line. I also put ", " between each integer in the output and put opening and closing brackets. The final line has fewer items than the previous lines if the List has a Count that is not a multiple of the number of items per line. For example, if the List had 49 integers and the method was called to put 11 items on each line, the output string, when printed, would look something like this:

[3397, 3398, 3401, 3403, 3409, 3415, 3418, 3419, 3421, 3427, 3431, 
3437, 3439, 3442, 3443, 3446, 3453, 3455, 3459, 3466, 3473, 3481,
3482, 3487, 3489, 3493, 3494, 3497, 3503, 3505, 3506, 3513, 3518,
3521, 3523, 3543, 3545, 3551, 3554, 3561, 3563, 3566, 3569, 3574,
3578, 3579, 3587, 3589, 3595]

I already wrote a method that does this, and the output looks great, but I feel like my code may be suffering from spaghetti/jank. Is there a better way to do this, using fewer lines of code and using StringBuilder instead of string concatenation?

public static string MakeBigStringFromList(List<int> input, 
            int itemsPerLine)
{
    int length = input.Count;
    List<int>.Enumerator intEnumerator = input.GetEnumerator();
    string bigReturnString = "[";
    if (length > 0)
    {
        intEnumerator.MoveNext();
        bigReturnString  = intEnumerator.Current.ToString();
        if (length > 1)
        {
            bigReturnString  = ", ";
        }
    }
    int firstTime = 1;

    int i = 1;
    while (i < length)
    {
        string line = "";
        int j = 0   firstTime;
        if (i   itemsPerLine < length)
        {
            while (j < itemsPerLine)
            {
                intEnumerator.MoveNext();
                line  = intEnumerator.Current.ToString()   ", ";
                i  ;
                j  ;
            }
            bigReturnString  = line   "\n";
            firstTime = 0;
        }
        else
        {
            while (i < (length - 1))
            {
                intEnumerator.MoveNext();
                line  = intEnumerator.Current.ToString()   ", ";
                i  ;
            }
            intEnumerator.MoveNext();
            line  = intEnumerator.Current.ToString();
            i  ;
            bigReturnString  = line;
            intEnumerator.Dispose();
        }
    }

    bigReturnString  = "]";
    return bigReturnString;
}

CodePudding user response:

Yes, you could make it a "little bit" shorter and more readable, for example with LINQ

var intsPerLine = list.Select((i, index) => (Integer: i, Index: index))
    .GroupBy(x => x.Index / 11, x => x.Integer.ToString())
    .Select(g => string.Join(", ", g)   ",");
string result = $"[{string.Join(Environment.NewLine, intsPerLine).TrimEnd(',')}]";

String.Join is using a StringBuilder under the hood, so this is not inefficient.

Explanation: Group all ints into packages of 11 with integer division, select the int as string:

GroupBy(x => x.Index / 11, x => x.Integer.ToString())

These 11 ints are concatendated with comma, so you get multiple strings:

Select(g => string.Join(", ", g)   ",")

Build the final string by using String.Join on these line-strings with Environment.NewLine. The last comma is removed and then wrap it in brackets:

$"[{string.Join(Environment.NewLine, intsPerLine).TrimEnd(',')}]

The result is same as yours(apart from that you use "\n" and i use Environment.NewLine).

CodePudding user response:

If you are on .NET6, you can make use of the Chunk LINQ method:

string BuildString(IEnumerable<int> list, int countPerLine)
{
    return "[" 
          string.Join(Environment.NewLine, 
            list.Chunk(countPerLine).Select(c => string.Join(", ", c)   ","))
            .TrimEnd(',') 
          "]";
}

Chunk will split the input into sub-sequences of at most countPerLine elements. Then string.Join(", ", c) "," creates a line from each of the sub-sequences, and finally string.Join(Environment.NewLine, ...) combines these lines.

  • Related