在C#中是否存在带有“命名行”的“DataTable”?

时间:2013-06-27 16:17:46

标签: c#

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

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只有命名列...

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

3 个答案:

答案 0 :(得分:4)

虽然您可以使用Dictionary<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;
    }
}

请注意,如果您愿意在构造时修改行/列,那么您将能够使用T[,]作为数据的支持,这将使该类更容易实现,并且进一步减少内存开销,尽管这似乎不适用于您的用例。

答案 1 :(得分: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];

答案 2 :(得分:0)

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

您可以使用列表&lt;&gt;通用存储它和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;

由于行/列名称的重复,它将占用大量资源,但您确实可以为小型数据集提供很大的灵活性。

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