Есть ли полиморфный 2D-тип коллекции, который включает массивы в c #? - PullRequest
0 голосов
/ 02 января 2019

Допустим, у меня есть вспомогательный класс, который содержит методы, управляющие коллекцией:

public static void RemainingDegreeDistribution(IGraph graph, float[,] distArr)
{
    int total = 0;
    for(int i=0; i < graph.Edges.Count; i++)
    {
        int startRemDeg = graph.Edges[i].Start.RemDeg;
        int endRemDeg = graph.Edges[i].End.RemDeg;
        distArr[startRemDeg,endRemDeg]++;
        distArr[endRemDeg, startRemDeg]++;
        total = total+2;
    }

    for(int i=0; i < distArr.GetLength(0); i++)
    {
        for(int j=0; j < distArr.GetLength(1); j++)
        {
            distArr[i,j] /= total;
        }
    }
}

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

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

Я хочу иметь возможность повторно использовать код для обоих случаев и избегать введения множества уродливой условной логики. Мне также нужно избегать выделения памяти, поэтому создание какого-либо класса-оболочки для массивов неприемлемо. Я также хочу избежать использования списков в списках, так как с обычными 2d-массивами работать намного проще, и списки выделяют слишком много памяти для моих целей. Кажется, что это должно быть возможно с индексаторами или что-то. Например, есть способ объявить, что «distArr» должен быть любого типа с индексатором, который принимает два аргумента и т. Д .?

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Нет такого интерфейса.Поэтому вам нужно создать свой собственный, например:

public interface IMatrix<T>
{
    int Rows { get; }
    int Columns { get; }
    ref T this[int row, int column] { get; }
}

и дополнительно реализовать его в ваших классах коллекций, создать адаптер для массивов ( Pattern Adapter ).

Я знаю, я знаю, вы сказали

Мне также нужно избегать выделения памяти, поэтому создание какого-либо класса-оболочки для массивов недопустимо.

Я не думаю, что крошечный недолговечный объект-оболочка поколения GC3 повредит вашей системе, но в любом случае можно избежать выделения кучи, реализовав оболочку как struct:

public struct ArrayMatrix<T> : IMatrix<T>
{
    readonly T[,] source;
    public ArrayMatrix(T[,] source) => this.source = source;
    public int Rows => source.GetLength(0);
    public int Columns => source.GetLength(1);
    public ref T this[int row, int column] => ref source[row, column];
}

иделая ваш метод generic (чтобы избежать блокировки struct):

public static void RemainingDegreeDistribution<TMatrix>(IGraph graph, TMatrix distArr)
    where TMatrix : IMatrix<float>
{
    int total = 0;
    for (int i = 0; i < graph.Edges.Count; i++)
    {
        int startRemDeg = graph.Edges[i].Start.RemDeg;
        int endRemDeg = graph.Edges[i].End.RemDeg;
        distArr[startRemDeg, endRemDeg]++;
        distArr[endRemDeg, startRemDeg]++;
        total = total + 2;
    }

    for (int i = 0; i < distArr.Rows; i++)
    {
        for (int j = 0; j < distArr.Columns; j++)
        {
            distArr[i, j] /= total;
        }
    }
}

Чтобы упростить использование с массивами, вы можете добавить вспомогательный метод:

public static class ArrayMatrix
{
    public static ArrayMatrix<T> ToMatrix<T>(this T[,] source) => new ArrayMatrix<T>(source);
}

и даже обеспечивают перегрузку вашего метода аргументом массива:

public static void RemainingDegreeDistribution(IGraph graph, float[,] distArr)
    => RemainingDegreeDistribution(graph, distArr.ToMatrix());
0 голосов
/ 02 января 2019

Если вам нужно представить точку в 2D-пространстве, я предлагаю вам использовать структуру данных Point. https://docs.microsoft.com/en-us/dotnet/api/system.drawing.point?view=netframework-4.7.2

Попробуйте перегрузить, если вы также передадите массив координат и точек:

public static Method ( float[,] coordinates )
{
     //generate array of Points starting from coordinates , points.Add ( new Point(coordinate[i,j]) )
}

public static Method ( Point[] points)
{
     //actual logic
}
...