0

JobDetailID と CalculatedID の 2 つの列を持つ DataTable があります。JobDetailID は常に一意であるとは限りません。特定の JobDetailID の CalculatedID の 1 つまたは最初のインスタンスを JobDetailID + "A" にする必要があり、同じ JobDetailID を持つ行が複数ある場合は、連続する行を JobDetailID + "B"、"C" などにする必要があります。同じ JobDetailID を持つ行が 4 つまたは 5 つ以下であること。

現在、次のように実装していますが、許容できないほど遅いです。

private void AddCalculatedID(DataTable data)
{
    var calculatedIDColumn = new DataColumn { DataType = typeof(string), ColumnName = "CalculatedID" };
    data.Columns.Add(calculatedIDColumn);
    data.Columns["CalculatedID"].SetOrdinal(0);

    var enumerableData = data.AsEnumerable();

    foreach (DataRow row in data.Rows)
    {
        var jobDetailID = row["JobDetailID"].ToString();

        // Give calculated ID of JobDetailID + A, B, C, etc. for multiple rows with same JobDetailID
        int x = 65; // ASCII value for A
        string calculatedID = jobDetailID + (char)x;

        while (string.IsNullOrEmpty(row["CalculatedID"].ToString()))
        {
            if ((enumerableData
                .Any(r => r.Field<string>("CalculatedID") == calculatedID)))
            {
                calculatedID = jobDetailID + (char)x;
                x++;
            }
            else
            {
                row["CalculatedID"] = calculatedID;
                break;
            }
        }
    }
}

この形式の出力に固執する必要があると仮定すると、このパフォーマンスをどのように改善できますか?

4

4 に答える 4

0

これをLINQとしてタグ付けしましたが、反復法を使用しています。おそらくこれを行うための最良の方法は、両方の組み合わせを使用し、各「グループ化」を繰り返し、グループ化の各行に計算されたIDを割り当てることです。

foreach (var groupRows in data.AsEnumerable().GroupBy(d => d["JobDetailID"].ToString()))
{
    if(string.IsNullOrEmpty(groupRows.Key))
        continue;

    // We now have each "grouping" of duplicate JobDetailIDs.
    int x = 65; // ASCII value for A
    foreach (var duplicate in groupRows)
    {
        string calcID = groupRows.Key + ((char)x++);
        duplicate["CalculatedID"] = calcID;
        //Can also do this and achieve same results.
        //duplicate["CalculatedID"] = groupRows.Key + ((char)x++);
    }
}

最初に行うことは、重複する列をグループ化することです。これらの各グループを繰り返し処理し、すべてのグループのサフィックス値をリセットします。グループ化のすべての行について、計算されたIDを取得し(同時にサフィックス値をインクリメント)、重複する行にIDを割り当てます。ちなみに、ここで列挙している項目を変更していますが、これは通常は悪いことです。ただし、列挙型宣言(GroupBy)に関連付けられていないデータを変更しているため、列挙型の動作は変更されません。

于 2012-12-26T17:23:52.320 に答える
0

データを取得する場所に CalculatedID を生成するためのコードを追加することをお勧めしますが、それが利用できない場合は、重複が見つかるたびにテーブル全体をスキャンすることを避けたい場合があります。Dictionary次のように、使用するキーにa を使用できます。

private void AddCalculatedID(DataTable data)
{
    var calculatedIDColumn = new DataColumn { DataType = typeof(string), ColumnName = "CalculatedID" };
    data.Columns.Add(calculatedIDColumn);
    data.Columns["CalculatedID"].SetOrdinal(0);

    Dictionary<string, string> UsedKeyIndex = new Dictionary<string, string>();

    foreach (DataRow row in data.Rows)
    {
        string jobDetailID = row["JobDetailID"].ToString();
        string calculatedID;

        if (UsedKeyIndex.ContainsKey(jobDetailID))
        {
          calculatedID = jobDetailID + 'A';
          UsedKeyIndex.Add(jobDetailID, 'A');
        }
        else
        {
           char nextKey = UsedKeyIndex[jobDetailID].Value+1;
           calculatedID = jobDetailID + nextKey;
           UsedKeyIndex[jobDetailID] = nextKey;
        }

        row["CalculatedID"] = calculatedID;
    }
}

これは、生成されたキーに使用された最後の文字とともに、使用されたすべての JobDetailID をキャッシュするため、基本的にメモリを速度と交換します。これらの JobDetailID が非常に多くある場合、これは少しメモリを集中的に使用する可能性がありますが、何百万行も処理する必要がない限り、問題が発生することはないと思います。

于 2012-12-26T16:49:41.320 に答える
0

行に CalculatedID を設定するというあなたの考えを理解していれば、次のアルゴリズムでうまくいき、その複雑さは線形です。最も重要な部分はdata.Select("","JobDetailID")、ソートされた行のリストを取得する場所です。自分でコンパイルしたわけではないので、構文エラーがある可能性があります。

private void AddCalculatedID(DataTable data)
{
    var calculatedIDColumn = new DataColumn { DataType = typeof(string), ColumnName = "CalculatedID" };
    data.Columns.Add(calculatedIDColumn);
    data.Columns["CalculatedID"].SetOrdinal(0);

    int jobDetailID = -1;
    int letter = 65;
    foreach (DataRow row in data.Select("","JobDetailID"))
    {
        if((int)row["JobDetailID"] == jobDetailID)
        {
            row["CalculatedID"] = row["JobDetailID"].ToString() + (char)letter;
            letter++;
        }
        else
        {
            letter = 65;
            jobDetailID = (int)row["JobDetailID"];
        }
    }
}
于 2012-12-26T17:02:53.997 に答える