将 for 循环转换为带索引的 foreach

convert for loop to foreach with index

我有这个ToString方法用来写出对象。我正在尝试将 for 循环转换为 foreach 循环。 不使用 LINQ。

任何指点将不胜感激。

 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();
 } 

这里是基于您当前代码的重构。

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();
} 

使用 linq,您可以使用索引 Select 执行相同的操作,而无需直接调用后台使用的 foreach

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();
} 

从技术上讲,您可以这样做:

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();
}

无论如何,你都会选择 int index。按照 performance 将其移动到 foreach 时没有太大帮助。

如果您真的不喜欢到处编写递增索引,您也可以尝试自己的 ForEach 扩展。

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++;
        }
    }
}

那么你的方法会更简单,但你还有一个 class 需要管理:

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();
}

为了可读性,如果您真的只是并排放置字符串:

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 无论如何,在性能方面会更受欢迎。如果您需要格式化,请选择其他选项。

根据 totalcount 是什么,您可以重构为如下内容:

public override string ToString()
{
    return count.ToString()
        + String.Join(" ",
            array.Select((x, n) => $"{x}{x.GetInfo}{String.Join(" ", x.Content(n))}"));
}

String.Join 通常比 StringBuilder 表现更好,所以它是一个不错的选择。


给你。此扩展不需要 LINQ:

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++);
        }
    }
}