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;

私の知る限り、DataTableには名前付きの列しかありません...

編集:列または行の名前を変更する必要はありません。ただし、テーブルの中央に新しい行を挿入する必要がある場合があります。

4

3 に答える 3

4

a を使用し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[,]、データのバッキングとして a を使用できることに注意してください。これにより、クラスの実装が劇的に簡単になり、メモリのオーバーヘッドがさらに削減されますが、あなたのユースケースではうまくいかないようです。

于 2013-06-27T16:31:26.733 に答える
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 に答える