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 int
s into packages of 11 with integer division, select the int as string:
GroupBy(x => x.Index / 11, x => x.Integer.ToString())
These 11 int
s 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.