簡體   English   中英

具有動態列數的平面文件規范化

[英]Flat file normalization with a dynamic number of columns

我有一個平面文件,不幸的是動態列結構。 值中包含一個值,層次結構中的每個層都有自己的列。 例如,我的平面文件可能類似於:

StatisticID|FileId|Tier0ObjectId|Tier1ObjectId|Tier2ObjectId|Tier3ObjectId|Status
1234|7890|abcd|efgh|ijkl|mnop|Pending
...

第二天相同的飼料可能類似於:

StatisticID|FileId|Tier0ObjectId|Tier1ObjectId|Tier2ObjectId|Status
1234|7890|abcd|efgh|ijkl|Complete
...

問題是,我並不關心所有層級; 我只關心最后(底部)層的id,以及不屬於層列的所有其他行數據。 我需要將feed標准化為類似於此的東西以注入關系數據庫:

StatisticID|FileId|ObjectId|Status
1234|7890|ijkl|Complete
...

什么是一種有效的,易於閱讀的機制,用於確定最后一層的對象ID,並按照描述組織數據? 我所做的每一次嘗試都讓我感到尷尬。

我做過的一些事情:

  • 我試圖檢查正則表達式模式的列名,識別分層的列,按名稱降序排序,然后選擇第一條記錄......但是我這樣丟失了序數列號,所以看起來沒那么好。
  • 我已經將我想要的列放入IDictionary<string, int>對象中進行引用,但是再次可靠地收集動態列的序數是一個問題,而且看起來這似乎是非高效的。

幾年前我遇到了一個類似的問題。 我使用字典來映射列,它不漂亮,但它工作。

首先制作一個詞典:

private Dictionary<int, int> GetColumnDictionary(string headerLine)
    {
        Dictionary<int, int> columnDictionary = new Dictionary<int, int>();
        List<string> columnNames = headerLine.Split('|').ToList();

        string maxTierObjectColumnName = GetMaxTierObjectColumnName(columnNames);
        for (int index = 0; index < columnNames.Count; index++)
        {
            if (columnNames[index] == "StatisticID")
            {
                columnDictionary.Add(0, index);
            }

            if (columnNames[index] == "FileId")
            {
                columnDictionary.Add(1, index);
            }

            if (columnNames[index] == maxTierObjectColumnName)
            {
                columnDictionary.Add(2, index);
            }

            if (columnNames[index] == "Status")
            {
                columnDictionary.Add(3, index);
            }
        }

        return columnDictionary;
    }

    private string GetMaxTierObjectColumnName(List<string> columnNames)
    {
        // Edit this function if Tier ObjectId is greater then 9
        var maxTierObjectColumnName = columnNames.Where(c => c.Contains("Tier") && c.Contains("Object")).OrderBy(c => c).Last();

        return maxTierObjectColumnName;
    }

之后它只是通過文件運行:

private List<DataObject> ParseFile(string fileName)
    {
        StreamReader streamReader = new StreamReader(fileName);

        string headerLine = streamReader.ReadLine();
        Dictionary<int, int> columnDictionary = this.GetColumnDictionary(headerLine);

        string line;
        List<DataObject> dataObjects = new List<DataObject>();
        while ((line = streamReader.ReadLine()) != null)
        {
            var lineValues = line.Split('|');

            string statId = lineValues[columnDictionary[0]];
            dataObjects.Add(
                new DataObject()
                {
                    StatisticId = lineValues[columnDictionary[0]],
                    FileId = lineValues[columnDictionary[1]],
                    ObjectId = lineValues[columnDictionary[2]],
                    Status = lineValues[columnDictionary[3]]
                }
            );
        }

        return dataObjects;
    }

我希望這有助於(甚至一點點)。

就個人而言,我不會嘗試重新格式化您的文件。 我認為最簡單的方法是從前面后面解析每一行。 例如:

itemArray = getMyItems();
statisticId = itemArray[0];
fileId = itemArray[1];
//and so on for the rest of your pre-tier columns

//Then get the second to last column which will be the last tier
lastTierId = itemArray[itemArray.length -1];

既然你知道最后一層將始終是第二層,你可以從最后開始,繼續前進。 這似乎比嘗試重新格式化數據文件容易得多。

如果您確實想要創建新文件,可以使用此方法獲取要寫出的數據。

我不知道C#語法,但是沿着這些方向:

  1. 用|分割部分分割線 作為分隔符
  2. 得到零件[0],[1],[長度 - 2]和[長度 - 1]
  3. 將部件傳遞給數據庫處理代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM