Reputation: 1228
I have this ToString
method used to write out objects. I'm trying to convert the for
loop to a foreach
loop.
Without using LINQ.
Any pointers will be appreciated.
public override string ToString()
{
StringBuilder output = new StringBuilder();
output.AppendFormat("{0}", count);
for (var index = 0; index < total; index++)
{
output.AppendFormat("{0}{1}{2} ", array[index], array[index].GetInfo,
string.Join(" ", array[index].Content(index)),
);
}
return output.ToString();
}
Upvotes: 2
Views: 1167
Reputation: 117027
Depending on what total
and count
are, you could refactor to something like this:
public override string ToString()
{
return count.ToString()
+ String.Join(" ",
array.Select((x, n) => $"{x}{x.GetInfo}{String.Join(" ", x.Content(n))}"));
}
String.Join
can often perform better than StringBuilder
so it's not a bad alternative.
There you go. No LINQ required with this extension:
public static class Ex
{
public static IEnumerable<R> Select<T, R>(this IEnumerable<T> source, Func<T, int, R> projection)
{
int index = 0;
foreach (var item in source)
{
yield return projection(item, index++);
}
}
}
Upvotes: 2
Reputation: 247018
Here is a refactoring based on your current code.
public override string ToString() {
var output = new StringBuilder();
output.AppendFormat("{0}", count);
var index = 0;
foreach (var item in array) {
if (item!=null) {
output.AppendFormat("{0}{1}{2} ", item, item.GetInfo,
string.Join(" ", item.Content(index++)),
);
}
}
return output.ToString();
}
Using linq you could perform the same with a indexed Select
without directly calling the foreach which is used under the hood
public override string ToString() {
var output = new StringBuilder();
output.AppendFormat("{0}", count);
array.Select((item, index) =>
output.AppendFormat("{0}{1}{2} ", item, item.GetInfo,
string.Join(" ", item.Content(index)),
)
);
return output.ToString();
}
Upvotes: 3
Reputation: 1086
Technically, you can do something like this:
public override string ToString()
{
StringBuilder output = new StringBuilder();
output.Append(count);
int index = 0;
foreach (var item in array)
{
output.Append($"{item}{item.GetInfo()}{string.Join(" ", item.Content(index))}");
index++;
}
return output.ToString();
}
In any case, you're going to go for an int index
anyway. Not so much of an help when it comes to moving it to foreach as per the performance
goes.
You might try your own ForEach extension too if you really don't like writing incrementing indexes everywhere.
public static class EnumerableExtensions
{
public static void ForEachWithIndex<T>(this IEnumerable<T> sequence, Action<int, T> action)
{
// argument null checking omitted
int i = 0;
foreach (T item in sequence)
{
action(i, item);
i++;
}
}
}
Then your method would be even simpler but you'd have one more class to manage:
public override string ToString()
{
StringBuilder output = new StringBuilder();
output.Append(count);
array.ForEachWithIndex((index, item) => output.Append($"{item}{item.GetInfo()}{string.Join("", item.Content(index))}"));
return output.ToString();
}
And for readability, if you really are just putting strings side by side:
public override string ToString()
{
StringBuilder output = new StringBuilder();
output.Append(count);
array.ForEachWithIndex((index, item) => output.Append(
string.Concat(
item,
item.GetInfo(),
string.Join("", item.Content(index))
)));
return output.ToString();
}
As string.Concat
would be more appreciated performance wise anyway. Opt for the others if you need formatting.
Upvotes: 2