6

我需要一个具有命名列和行的数据结构。例如:

magic_data_table:

        col_foo col_bar
row_foo    1       3 
row_bar    2       4

我需要能够访问像magic_data_table["row_foo", "col_bar"](这会给我3)这样的元素

我还需要能够添加新列,例如:

magic_data_table.Columns.Add("col_new");
magic_data_table["row_foo", "col_new"] = 5;

AFAIK,DataTable 只有命名列...

编辑:我不需要更改列或行的名称。但是,我可能需要在表格中间插入新行。

4

3 回答 3

4

虽然您可以使用 aDictionary<string, Dictionary<string, T>>来做您想做的事,但这在内存方面并不是特别有效,并且可能会使内部字典不同步。如果您创建自己的数据结构,尽管这是列表的外观,使用字典将列名映射到索引,那么它很简单:

public class MyDataStructure<T>//TODO come up with better name
{
    private Dictionary<string, int> columns;
    private Dictionary<string, int> rows;
    private List<List<T>> data;

    public MyDataStructure(
            IEnumerable<string> rows,
            IEnumerable<string> columns)
    {
        this.columns = columns.Select((name, index) => new { name, index })
            .ToDictionary(x => x.name, x => x.index);

        this.rows = rows.Select((name, index) => new { name, index })
            .ToDictionary(x => x.name, x => x.index);

        initData();
    }

    private void initData()
    {
        data = new List<List<T>>(rows.Count);
        for (int i = 0; i < rows.Count; i++)
        {
            data.Add(new List<T>(columns.Count));
            for (int j = 0; j < columns.Count; j++)
            {
                data[i].Add(default(T));
            }
        }
    }

    public T this[string row, string column]
    {
        //TODO error checking for invalid row/column values
        get
        {
            return data[rows[row]][columns[column]];
        }
        set
        {
            data[rows[row]][columns[column]] = value;
        }
    }

    public void AddColumn(string column)
    {
        columns.Add(column, columns.Count);
        for (int i = 0; i < data.Count; i++)
        {
            data[i].Add(default(T));
        }
    }

    public void AddRow(string row)
    {
        rows.Add(row, rows.Count);
        var list = new List<T>(columns.Count);
        data.Add(list);
        for (int i = 0; i < columns.Count; i++)
        {
            list.Add(default(T));
        }
    }

    public bool RenameRow(string oldRow, string newRow)
    {
        if (rows.ContainsKey(oldRow) && !rows.ContainsKey(newRow))
        {
            this.Add(newRow, rows[oldRow]);
            this.Remove(oldRow);
            return true;
        }

        return false;
    }
}

请注意,如果您愿意在构造时修复行/列,那么您将能够使用 aT[,]作为数据的支持,这既可以大大简化类的实现,又可以进一步减少内存开销,尽管那似乎不适用于您的用例。

于 2013-06-27T16:31:26.733 回答
3

在下面为名称添加一列 - “名称”:

DataTable table = ...
DataColumn nameCol = table.Columns["name"];
var index = table.Rows.Cast<DataRow>()
    .ToDictionary(row => (string)row[nameCol]);

... // then when you need the values:

string rowName = ..., colName = ...
var val = index[rowName][colName];
于 2013-06-27T16:36:20.813 回答
0

您可能会发现 Tuple(.net 4.0 及更高版本)类适合您的需要。它不会像桌子那样严格地工作,但会给你很大的灵活性。

您可以使用 List<> 泛型来存储它并使用 LINQ 来查询您的数据。

List<Tuple<string, string, int>> magicTable = new List<Tuple<string, string, int>>();

magicTable.AddRange(new Tuple<string, string, int>[] {
    Tuple.Create("row_foo", "col_foo", 1),
    Tuple.Create("row_foo", "col_bar", 2),
    Tuple.Create("row_bar", "col_foo", 3),
    Tuple.Create("row_bar", "col_bar", 4)});

magicTable.Add(Tuple.Create("row_foo", "col_new", 5));

int value = magicTable.Single(tuple => (tuple.Item1 == "row_foo" && tuple.Item2 == "col_new")).Item3;

由于行/列名称的重复,这将占用大量资源,但对于小型数据集,您确实获得了很大的灵活性。

Microsoft 的元组文档(3 元组):http: //msdn.microsoft.com/en-us/library/dd387150.aspx

于 2013-06-27T18:27:56.780 回答