我需要一个包含命名列和行的数据结构。例如:
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只有命名列...
编辑: 我不需要更改列或行的名称。但是,我可能需要在表格的中间插入新的行。
答案 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