2012-12-26 1 views
0

나는 JobDetailID와 CalculatedID 두 개의 열이있는 DataTable을 가지고있다. JobDetailID는 항상 고유하지 않습니다. 주어진 JobDetailID에 대한 CalculatedID의 첫 번째 인스턴스를 JobDetailID + "A"로하고, 동일한 JobDetailID를 가진 여러 행이있을 때 연속적인 행을 JobDetailID + "B", "C"등으로 만들고 싶습니다. 동일한 JobDetailID를 가진 행이 4 ~ 5 개를 넘지 않습니다.DataTable에서 값을보다 효율적으로 할당하는 방법은 무엇입니까?

나는 현재는 다음과 같이 구현하지만, 허용 할 수 없을 정도로 느린 :

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; 
      } 
     } 
    } 
} 

나는이 성능을 개선시킬 수있는 방법, 나는 출력이 형식을 준수해야하는 가정?

+1

데이터를 가져 오는 proc에서 계산을 수행 할 수 있습니까? 가장 우아한 해결책은 아니지만 결과 집합을 반복하여 열을 추가하는 것입니다. 어쩌면 proc에서 calc를 수행하고 위의 코드를 피하는 것이 좋습니다. 어쩌면 가장 좋은 질문은 데이터를 어떻게 얻는 것입니까? –

+0

처음에는 'DataTable'을 어떻게 채우고 있습니까? 데이터베이스 밖에 있다면이 열을 계산하는 것이 좋습니다. –

+0

@SPFiredrake의 답변은 매우 판독 가능합니다 (보통 비 핵심 성능보다 선호). 그러나 "가장 빠름"은 아닙니다. 신속한 방법으로 작업하고 제안 된 답으로 답장을 보내주십시오. – DanielCuadra

답변

0

데이터를 가져 오는 위치에 CalculatedID를 생성하는 코드를 추가하는 것이 좋지만, 사용할 수없는 경우 중복이 발견 될 때마다 전체 테이블을 검색하지 않는 것이 좋습니다. 이 같은 사용 키위한 Dictionary을 사용할 수 있습니다

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가 많고 많은 경우 약간 메모리가 많이 소모 될 수 있지만 수백만 개의 행을 처리하지 않으면 문제가 발생할 수 있습니다.

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"]; 
     } 
    } 
} 
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)과 관련이없는 데이터를 변경하므로 열거 형 동작을 변경하지 않습니다.

0

이 방법은 한 번에 작업을 완료합니다. 예를 들어 "JobDetailID"가 문자열이 아닌 정수 인 경우 또는 DataTable이 항상 "JobDetailID"로 정렬 된 데이터를 수신하는 경우 (사전을 제거 할 수 있음), 여기에 초안이 있습니다.

private static void AddCalculatedID(DataTable data) 
    { 
     data.BeginLoadData(); 

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

      var jobDetails = new Dictionary<string, int>(data.Rows.Count); 

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

       if (jobDetails.TryGetValue(jobDetailID, out lastSuffix)) 
       { 
        lastSuffix++; 
       } 
       else 
       { 
        // ASCII value for A 
        lastSuffix = 65; 
       } 

       row["CalculatedID"] = jobDetailID + (char)lastSuffix; 
       jobDetails[jobDetailID] = lastSuffix; 
      } 
     } 
     finally 
     { 
      data.EndLoadData(); 
     } 
    } 
관련 문제