Многомерная структура данных в C#

Я хочу построить структуру данных, которая в основном представляет собой матрицу строк со следующим.

  1. Растущее количество строк
  2. ФИКСИРОВАННОЕ количество столбцов

Я хочу иметь возможность получить доступ к тому, что находится в определенной строке или столбце, с помощью вызова метода, который принимает целочисленную строку no и номер int col в качестве аргумента. Кроме того, я хочу иметь возможность установить значение столбца, используя строку и номер столбца.

Я мог бы сделать это сам, но готов посмотреть, что могут сделать другие люди...

РЕДАКТИРОВАТЬ Извините, список столбцов будет исправлен, моя ошибка :-(


person AJM    schedule 08.06.2009    source источник
comment
Хороший вопрос, но не могли бы вы нарисовать картинку, чтобы добавить некоторый контекст, например (ожидаемые) размеры, как часто можно добавлять строки/столбцы и т. д.   -  person Henk Holterman    schedule 08.06.2009
comment
столбцы будут зафиксированы. Это будет серверная часть компонента пользовательского интерфейса, где пользователь может добавлять новые записи, чтобы строки можно было добавлять довольно часто. Не иметь дело с большими объемами данных (менее 20 записей)   -  person AJM    schedule 08.06.2009
comment
Редактирование (фиксированные столбцы) переворачивает его на бок. DataTable будет лучше. Но не так интересно.   -  person Henk Holterman    schedule 09.06.2009
comment
Что вы пробовали до сих пор?   -  person user1451111    schedule 31.08.2019


Ответы (6)


DataTable и DataSet (в основном набор таблицы данных) отлично подойдет для того, что вы ищете.

Затем вы можете получить доступ к своим данным (после того, как вы настроили столбцы и добавили свои строки данных) с помощью следующего синтаксиса:

datatable.rows(index)("ColumnName")

or

datatable.rows(rowindex)(columnindex)
person TheTXI    schedule 08.06.2009

Мне кажется, что таблица данных была бы самым простым вариантом.

person Kane    schedule 08.06.2009

Если вам нужно более двух измерений или вы хотите более универсальное решение, вы можете заставить его работать с List<List<T>>, вложенным настолько глубоко, насколько это необходимо, и обернутым в пользовательский тип, если вам нужна более конкретная функциональность или вы хотите более простые вызовы методов.

person Tomas Aschan    schedule 08.06.2009
comment
если у них есть ключ или идентификатор, вы можете использовать SortedList‹int,List‹T›› для более быстрого доступа. - person Marcom; 08.06.2009

Как насчет того, чтобы основывать что-то на Dictionary<System.Drawing.Point, string>? Чтобы вы могли писать;

stringGrid.Add(new Point(3,4), "Hello, World!");

Создайте класс, содержащий такой словарь, и тогда вы получите то, что ищете, почти бесплатно. Что-то вроде (не проверено)

class StringGrid
{
    Dictionary<System.Drawing.Point, string> grid;

    public StringGrid
    {
        this.grid = new Dictionary<System.Drawing.Point, string>();
    }

    public string Get(int x, int y)
    {
        string result = null;
        grid.TryGetValue(new Point(x,y), out result);
        return result;
    }

    public void Set(int x, int y, string content)
    {
        var pos = new Point(x,y);
        if (grid.ContainsKey(pos))
        {
            if (content == null)
            {
                // no content, so just clear the cell.
                grid.remove(pos);
            }
            else
            {
                // add new content
                grid[pos].Value = content;
            }  
        } 
        else if (content != null)
        {
            // new non-null content
            grid.add(pos, content);
        }
    }
}

РЕДАКТИРОВАТЬ: Кроме того, если вы хотите получить действительно вспышку;

  • заменить словарь на SortedList<,>
  • замените System.Drawing.Point своей собственной структурой, которая реализует IComparable

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

person Steve Cooper    schedule 08.06.2009
comment
Две вещи: 1) используйте индексаторы :) и 2) словарь точек не сохраняет матрицу прямоугольной. Я предполагаю, что № 2 имеет значение. - person Colin Burnett; 08.06.2009
comment
Это на самом деле приятно. И было бы легко свернуть для этого свои собственные индексаторы. Что касается прямоугольности, то... Я полагаю, что вы могли бы выровнять элементы по мере добавления столбцов или строк, но это потребует некоторой работы. Легче, если это разрешено быть зазубренным. - person Michael Todd; 08.06.2009
comment
Более или менее моя идея тоже, но я бы не стал использовать для этого Drawing.Point. Это так вне связи. Но технически все в порядке и готово к использованию. - person Henk Holterman; 08.06.2009
comment
Drawing.Point — да, наверное, лучше создать свою собственную структуру (это должна быть структура, иначе словарь не будет работать), но это будет точно такая же структура, как Drawing.Point. прямоугольная матрица - она ​​будет неограниченно расти, как чистая разреженная матрица. Не нужно об этом беспокоиться. Требуется операция O (n), чтобы найти размеры ограничивающей рамки, если это то, что требуется, но это не было указано. - person Steve Cooper; 08.06.2009
comment
@ Стив, вы, безусловно, можете использовать объекты в словаре в качестве ключей. Для этого вам необходимо реализовать Equals и GetHashCode, IEquatable‹T› или указать IEqualityComparer‹T› в конструкторе Dictionary. - person Colin Burnett; 09.06.2009
comment
@Colin - ты абсолютно прав; вы можете использовать класс. Я пытался сказать, что struct point { int x; int y } работает как ключ, а class point { int x; int y } - нет. - person Steve Cooper; 10.06.2009

Если бы я хотел/должен был свернуть свой собственный (скажем, я не хотел иметь дело с тем, что DataTable/DataSet), тогда я бы написал что-то вокруг List<List<T>> (или List<List<object>>) в виде списка строк, а затем столбцов с логикой, чтобы сохранить списки прямоугольный.

  • AddRow() добавит новую запись внешнего списка.
  • AddColumn() добавит новый элемент во все списки во внутреннем списке.
  • this[int row, int col] получит доступ к this._Data[row][col].

Что-то такое.

Переключитесь на Dictionary<K, List<V>>, если мне нужны именованные столбцы (тогда списки содержат данные строки для этого столбца).

person Colin Burnett    schedule 08.06.2009

Если вы хотите, чтобы его можно было расширять в обоих направлениях, DataTable — не лучший выбор.

Для интерфейса вы можете использовать свойство indexer:

class Foo 
{   
    public string this[int x, int y]
    {
        get { return GetData(x,y); }
    }
}

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

struct Index { public readonly int X, Y; }

и переопределить члены Equals() и GetHashCode(). Недавно на SO было несколько вопросов по этому поводу.

После этого используйте Dictionary < Index, string>

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

person Henk Holterman    schedule 08.06.2009