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