/// <summary>Populate table headers based on the specified layout.</summary>
        private void PopulateHeaders(VariantMatrix result)
        {
            MatrixLayout layout = result.Layout;

            // Populate row headers if they are specified by the layout
            if (layout.HasRowHeaders())
            {
                var rowHeaders = new List <string>();
                for (int rowIndex = 0; rowIndex < result.RowCount; rowIndex++)
                {
                    rowHeaders.Add($"Row{rowIndex}");
                }
                result.RowHeaders = rowHeaders.ToArray();
            }

            // Populate column headers if they are specified by the layout
            if (layout.HasColHeaders())
            {
                var colHeaders = new List <string>();
                for (int colIndex = 0; colIndex < result.ColCount; colIndex++)
                {
                    colHeaders.Add($"Col{colIndex}");
                }
                result.ColHeaders = colHeaders.ToArray();
            }

            // Populate corner header if it is specified by the layout
            if (layout.HasCornerHeader())
            {
                result.CornerHeader = "Corner";
            }
        }
Пример #2
0
        /// <summary>
        /// Create data containers inside the matrix and populate the values
        /// with default(T).
        ///
        /// This method also creates the row and column headers with the
        /// correct size, if the respective header is specified in the layout.
        /// </summary>
        public void Resize(MatrixLayout layout, int rowCount, int colCount)
        {
            Layout   = layout;
            RowCount = rowCount;
            ColCount = colCount;

            if (layout.HasRowHeaders())
            {
                RowHeaders = new string[rowCount];
            }
            if (layout.HasColHeaders())
            {
                ColHeaders = new string[colCount];
            }
        }
Пример #3
0
        /// <summary>
        /// Populate by parsing multi-line CSV text using the specified
        /// matrix layout and an array of column parser functions.
        ///
        /// If the data has more columns than the array of parsers,
        /// the last parser in the array is used for all additional
        /// columns. This permits ingesting CSV files with an unknown
        /// number of value columns of the same type, after an initial
        /// set of category columns that have other types.
        ///
        /// The specified parser is not used for row and column headers
        /// which are always dot delimited strings.
        /// </summary>
        public void ParseCsv(MatrixLayout layout, Func <string, T>[] colParsers, string csvText)
        {
            if (layout == MatrixLayout.Empty)
            {
                throw new Exception("Matrix layout passed to ParseCsv method is empty");
            }
            Layout = layout;

            // Parse into a list of text lines
            string[] csvLines = CsvUtil.TextToLines(csvText);

            // Parse each line into tokens, keeping track of maximum
            // size which will determine the matrix size
            int             rowCount   = csvLines.Length;
            List <string[]> parsedRows = new List <string[]>();
            int             colCount   = 0;

            foreach (string csvLine in csvLines)
            {
                string[] tokens = CsvUtil.LineToTokens(csvLine);
                if (colCount < tokens.Length)
                {
                    colCount = tokens.Length;
                }
                parsedRows.Add(tokens);
            }

            int colOffset = 0;

            if (layout.HasRowHeaders())
            {
                // First column is row headers, data has one less column
                colOffset = 1;
                colCount--;
            }

            int rowOffset = 0;

            if (layout.HasColHeaders())
            {
                // First row is column headers, data has one less row
                rowOffset = 1;
                rowCount--;
            }

            // Resize
            Resize(layout, rowCount, colCount);

            // Parse column headers if present
            if (rowOffset != 0)
            {
                string[] rowTokens = parsedRows[0];

                // Populate corner header if present
                if (colOffset != 0)
                {
                    CornerHeader = rowTokens[0];
                }

                // Populate column headers if present
                for (int colIndex = 0; colIndex < colCount; ++colIndex)
                {
                    string token = rowTokens[colOffset + colIndex];
                    ColHeaders[colIndex] = token;
                }
            }

            for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex)
            {
                string[] rowTokens = parsedRows[rowOffset + rowIndex];

                // Set row header if present
                if (colOffset != 0)
                {
                    RowHeaders[rowIndex] = rowTokens[0];
                }

                // Set row values
                for (int colIndex = 0; colIndex < colCount; ++colIndex)
                {
                    // If column index is outside the range of column parsers array,
                    // take the last element of the array instead. This permits
                    // parsing CSV data with unknown number of columns where trailing
                    // columns have the same type
                    int parserColIndex         = colIndex < colParsers.Length ? colIndex : colParsers.Length - 1;
                    Func <string, T> colParser = colParsers[parserColIndex];

                    string token = rowTokens[colOffset + colIndex];

                    values_[LinearIndex(rowIndex, colIndex)] = colParser(token);
                }
            }
        }