2017-10-20 77 views
0

我試圖找出實施以下情形的最有效的方式串:檢查列表包含匹配密切

我有一個這樣的名單:

public static IEnumerable<string> ValidTags = new List<string> { 
    "ABC.XYZ", 
    "PQR.SUB.UID", 
    "PQR.ALI.OBD", 
}; 

我有一個巨大的CSV與多列。其中一列是tags。此列包含空白值或上述值之一。問題是,標籤列可能包含「[email protected]」等值,即有效標籤加上一些無關字符。我需要使用有效標記更新這些列,因爲它們「」與我們的有效標記之一「」非常匹配。

例子:

  • 如果CSV包含PQR.ALI.OBD?與有效的標籤PQR.ALI.OBD
  • 如果CSV包含PQR.ALI.OBA更新它,這是無效的,只是加後綴無效和更新PQR.ALI.OBA-invalid

我試圖找出最好的方法來做到這一點。

我目前的做法是:

  1. 迭代通過CSV每一列,獲得tagValue
  2. 現在檢查,如果我們的tagValue包含任何從列表
  3. 字符串如果它包含但不完全一樣,請用它包含的值更新它。
  4. 如果它不包含列表中的任何值,請添加後綴無效。

有沒有更好/更有效的方法來做到這一點?

更新:

名單隻有5個項目,我已經在這裏顯示了三個。 額外的字符只是在最後,這是因爲人們在Excel Web版本中編輯這些CSV,並弄亂了一些條目。我現在的代碼:(我敢肯定有更好的方法來做到這一點,在C#中也是新的,所以請告訴我如何改善這一點)。我正在使用CSVHelper來獲取CSV單元格。

var record = csv.GetRecord<Record>(); 
string tag = csv.GetField(10); //tag column number in CSV is 10 
/* Criteria for validation: 
* tag matches our list, but has extraneous chars - strip extraneous chars and update csv 
* tag doesn't match our list - add suffix invalid.*/ 
int listIndex = 0; 
bool valid; 
foreach (var validTags in ValidTags) //ValidTags is the enum above 
{ 
    if (validTags.Contains(tag.ToUpper()) && !string.Equals(validTags, subjectIdentifier.ToUpper())) 
    { 
    valid = true; 
    continue; //move on to next csv row. 
    //this means that tag is valid but has some extra characters appended to it because of web excel, strip extra charts 

    } 
    listIndex++; 
    if(listIndex == 3 && !valid) { 
    //means we have reached the end of the list but not found valid tag 
    //add suffix invalid and move on to next csv row 
    } 
} 
+0

額外的字符總是在最後? – BurnsBA

+0

這些字面上是列表中唯一的三個項目嗎?或者任何列表項目是其他列表項目的子集(例如'ABC.XYZ'和'ABC.XYZ.PQR')? –

+1

你能分享你目前的做法嗎? – Gianlucca

回答

0

既然你說是多餘的角色僅在最後,假設原來的標籤仍然是前多餘的字符存在,則可以只搜索列表中的每個標籤,看標籤包含一個從列表中輸入。如果確實如此,則將其更新爲正確的條目(如果它不完全匹配),如果不匹配,則將「-invalid」標籤附加到它。

在做這件事之前,我們可能需要首先對降序列表進行排序,這樣當我們搜索時,我們會找到最接近的(最長的)匹配(在列表中的一個項目以列表中的另一個項目開始的情況下) 。

var csvPath = @"f:\public\temp\temp.csv"; 
var entriesUpdated = 0; 

// Order the list so we match on the most similar match (ABC.DEF before ABC) 
var orderedTags = ValidTags.OrderByDescending(t => t); 
var newFileLines = new List<string>(); 

// Read each line in the file 
foreach (var csvLine in File.ReadLines(csvPath)) 
{ 
    // Get the columns 
    var columns = csvLine.Split(','); 

    // Process each column 
    for (int index = 0; index < columns.Length; index++) 
    { 
     var column = columns[index]; 

     switch (index) 
     { 
      case 0: // tag column 
       var correctTag = orderedTags.FirstOrDefault(tag => 
        column.IndexOf(tag, StringComparison.OrdinalIgnoreCase) > -1); 

       if (correctTag != null) 
       { 
        // This item contains a correct tag, so 
        // update it if it's not an exact match 
        if (column != correctTag) 
        { 
         columns[index] = correctTag; 
         entriesUpdated++; 
        } 
       } 
       else 
       { 
        // This column does not contain a correct tag, so mark it as invalid 
        columns[index] += "-invalid"; 
        entriesUpdated++; 
       } 

       break; 

      // Other cases for other columns follow if needed 
     } 
    } 

    newFileLines.Add(string.Join(",", columns)); 
} 

// Write the new lines if any were changed 
if (entriesUpdated > 0) File.WriteAllLines(csvPath, newFileLines);