Как я могу предотвратить дублирование общего цикла в моем решении?

#c# #.net #code-duplication #jagged-arrays

#c# #.net #дублирование кода #зазубренные массивы

Вопрос:

У меня есть этот цикл, основанный на неровном массиве ниже, который мне нужно будет использовать более одного раза в разных местах.

Как я могу запретить себе переписывать этот цикл снова и снова, чтобы я мог его дублировать?

       foreach (int[] columns in rowsAndColumns)
      {
          foreach (int element in columns)
          {

          }
      }
  

Ответ №1:

Вы можете написать

 foreach (int element in rowsAndColumns.SelectMany(col => col))
{
    // ...
}
  

вместо этого. Если вам не нравится постоянно вводить это, вы можете абстрагировать это во вспомогательный метод:

 foreach (int element in rowsAndColumns.Flatten())
{
    // ...
}

// [...]

public IEnumerable<T> Flatten(this IEnumerable<IEnumerable<T>> source)
{
    return source.SelectMany(e => e);
}
  

Комментарии:

1. Еще раз я вспоминаю, что мне нужно лучше ознакомиться с SelectMany 😉

Ответ №2:

Это зависит от того, что вы хотите сделать, но если вы хотите выполнить действие для каждого int, вы могли бы использовать что-то вроде расширения ниже. Может быть целесообразна некоторая проверка на нуль.

 static class RowColExtension
{
    public static void Each(this int[][] rowCols, Action<int> a)
    {
        foreach (var r in rowCols)
        {
            foreach (var c in r)
            {
                a(c);
            }
        }
    }
}
  

Ответ №3:

Это зависит от того, что вы хотите сделать в цикле. Я бы подошел к этому так (непроверенный код из моей головы!):

 public static class MyHelper {
    public static void ForEach(this IEnumerable<int[]> rowsAndColumns, Action<int> action) {
        foreach (int[] columns in rowsAndColumns) {
             foreach (int element in columns) {
                 action(element);
             }
        }
    }
}
  

Теперь вы можете назвать это следующим образом:

 rowsAndColumns.ForEach(e => Console.WriteLine(e));
  

Ответ №4:

Метод расширения:

 // It's late and I'm tired, the array declaration might be off.
public static void Visit(this int[][] array, Action<int> visitor)
{
      foreach (int[] columns in array)
      {
          foreach (int element in columns)
          {
              visitor(element);
          }
      }
}

myArray.Visit(elem => Console.WriteLine(elem));
  

Вы также можете использовать Action<int,int> для получения строки.

Ответ №5:

Поскольку вы выполняете итерацию по всем элементам без учета строки или столбца, вам следует превратить ваш неровный массив в первоклассную структуру данных и реализовать IEnumerable итерацию по коллекции с использованием foreach . Одна и та же первоклассная структура данных может поддерживать индексаторы с одним аргументом и двумя аргументами, проверку диапазона и т.д.

Редактировать:

Вот один из подходов к использованию абстракции вместо манипулирования низкоуровневыми структурами данных. Это предполагает, что неровный массив был размещен в другом месте. В любом случае, суть в том, что теперь мы можем использовать foreach непосредственно в структуре данных:

 public class JaggedArray : IEnumerable<int>
{
    private int[][] array;

    public JaggedArray(int[][] array)
    {
        this.array = array;
    }

    public int this[int row, int column]
    {
        get { return array[row][column]; }
        set { array[row][column] = value; }
    }

    public IEnumerable<int[]> Rows
    {
        get { return array; }
    }

    public IEnumerator<int> GetEnumerator()
    {
        foreach (var row in array)
            foreach (var item in row)
                yield return item;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}