Beispiel #1
0
        /// <summary>
        /// Decomposes a column into repeat units by analysing the values of the column with increasing index.
        /// If a column value is repeated, the current range is finalized and a new range is started. At the end,
        /// a list of index ranges is returned. Inside each range the column values are guaranteed to be unique.
        /// </summary>
        /// <param name="col">Column to decompose.</param>
        /// <returns>List of integer ranges. Inside a single range the column values are ensured to be unique.</returns>
        public static IList <ContiguousIntegerRange> DecomposeIntoRepeatUnits(DataColumn col)
        {
            var result    = new List <ContiguousIntegerRange>();
            var alreadyIn = new HashSet <AltaxoVariant>();

            var currentRangeStart = 0;
            var currentRangeCount = 0;

            for (int i = 0; i < col.Count; i++)
            {
                if (alreadyIn.Contains(col[i]))
                {
                    alreadyIn.Clear();
                    result.Add(ContiguousIntegerRange.FromStartAndCount(currentRangeStart, currentRangeCount));
                    currentRangeStart = i;
                    currentRangeCount = 0;
                }

                alreadyIn.Add(col[i]);
                currentRangeCount++;
            }

            if (currentRangeCount > 0)
            {
                result.Add(ContiguousIntegerRange.FromStartAndCount(currentRangeStart, currentRangeCount));
            }

            return(result);
        }
Beispiel #2
0
 public void TestFromStartAndCount4A()
 {
     Assert.Throws(typeof(ArgumentOutOfRangeException), () =>
     {
         var r = ContiguousIntegerRange.FromStartAndCount(0, -1);
     });
 }
Beispiel #3
0
        public void TestFromStartAndCount3()
        {
            var r = ContiguousIntegerRange.FromStartAndCount(int.MaxValue, 0);

            Assert.IsTrue(r.IsEmpty);
            Assert.AreEqual(0, r.Count);
            Assert.AreEqual(0, r.LongCount);
            Assert.AreEqual(0, r.Start);
        }
Beispiel #4
0
        public void TestEmpty()
        {
            var r = new ContiguousIntegerRange();

            Assert.IsTrue(r.IsEmpty);
            Assert.AreEqual(0, r.Count);
            Assert.AreEqual(0, r.LongCount);
            Assert.AreEqual(0, r.Start);
        }
Beispiel #5
0
        public void TestFromFirstAndLastInclusive1()
        {
            var r = ContiguousIntegerRange.FromFirstAndLastInclusive(int.MinValue + 1, int.MaxValue);

            Assert.IsFalse(r.IsEmpty);
            Assert.AreEqual((long)uint.MaxValue, r.LongCount);
            Assert.AreEqual(int.MinValue + 1, r.Start);
            Assert.AreEqual(int.MaxValue, r.LastInclusive);
        }
Beispiel #6
0
        public void TestFromStartAndEndExclusive4()
        {
            var r = ContiguousIntegerRange.FromStartAndEndExclusive(int.MinValue, int.MaxValue);

            Assert.IsFalse(r.IsEmpty);
            Assert.AreEqual(uint.MaxValue, r.LongCount);
            Assert.AreEqual(int.MinValue, r.Start);
            Assert.AreEqual(int.MaxValue, r.EndExclusive);
        }
Beispiel #7
0
        public void TestFromStartAndEndExclusive2()
        {
            var r = ContiguousIntegerRange.FromStartAndEndExclusive(int.MinValue, int.MinValue);

            Assert.IsTrue(r.IsEmpty);
            Assert.AreEqual(0, r.Count);
            Assert.AreEqual(0, r.LongCount);
            Assert.AreEqual(0, r.Start);
        }
		public void TestEmpty()
		{
			var r = new ContiguousIntegerRange();

			Assert.IsTrue(r.IsEmpty);
			Assert.AreEqual(0, r.Count);
			Assert.AreEqual(0, r.LongCount);
			Assert.AreEqual(0, r.Start);
		}
Beispiel #9
0
 /// <summary>
 /// Finds the source row for a given value inside a given row range.
 /// </summary>
 /// <param name="srcXCol">Column where the value must be found.</param>
 /// <param name="xVal">Value to find.</param>
 /// <param name="range">Range of rows.</param>
 /// <returns>The row for which the element is equal to the value, or -1 if the value could not be found.</returns>
 private static int FindSrcXRow(DataColumn srcXCol, AltaxoVariant xVal, ContiguousIntegerRange range)
 {
     // Find the src row
     foreach (int idx in range)
     {
         if (srcXCol[idx] == xVal)
         {
             return(idx);
         }
     }
     return(-1);
 }
Beispiel #10
0
        /// <summary>
        /// Transpose transpose the table, i.e. exchange columns and rows
        /// this can only work if all columns in the table are of the same type
        /// </summary>
        /// <param name="srcTable">Table to transpose.</param>
        /// <param name="options">Options that control the transpose process.</param>
        /// <param name="destTable">Table in which the transposed table should be stored.</param>
        /// <exception cref="ArgumentNullException">
        /// </exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException">The data columns to transpose are not of the same type. The first column that has a deviating type is column number  + firstDifferentColumnIndex.ToString()</exception>
        public static void Transpose(this DataTable srcTable, DataTableTransposeOptions options, DataTable destTable)
        {
            if (null == srcTable)
            {
                throw new ArgumentNullException(nameof(srcTable));
            }
            if (null == destTable)
            {
                throw new ArgumentNullException(nameof(destTable));
            }
            if (object.ReferenceEquals(srcTable, destTable))
            {
                throw new ArgumentException(nameof(srcTable) + " and " + nameof(destTable) + " are identical. This inline transpose operation is not supported.");
            }

            int numberOfDataColumnsChangeToPropertyColumns = Math.Min(options.DataColumnsMoveToPropertyColumns, srcTable.DataColumnCount);

            int numberOfPropertyColumnsChangeToDataColumns = Math.Min(options.PropertyColumnsMoveToDataColumns, srcTable.PropertyColumnCount);

            // number of data columns in the destination table that originates either from converted property columns or from the label column which contains the column names
            int numberOfPriorDestDataColumns = numberOfPropertyColumnsChangeToDataColumns + (options.StoreDataColumnNamesInFirstDataColumn ? 1 : 0);

            var dataColumnsToTransposeIndices = ContiguousIntegerRange.FromStartAndEndExclusive(numberOfDataColumnsChangeToPropertyColumns, srcTable.DataColumnCount);

            if (!AreAllColumnsOfTheSameType(srcTable.DataColumns, dataColumnsToTransposeIndices, out var firstDifferentColumnIndex))
            {
                throw new InvalidOperationException("The data columns to transpose are not of the same type. The first column that has a deviating type is column number " + firstDifferentColumnIndex.ToString());
            }

            using (var suspendToken = destTable.SuspendGetToken())
            {
                destTable.DataColumns.ClearData();
                destTable.PropCols.ClearData();

                // 0th, store the data column names in the first column
                if (options.StoreDataColumnNamesInFirstDataColumn)
                {
                    var destCol = destTable.DataColumns.EnsureExistenceAtPositionStrictly(0, "DataColumnNames", typeof(TextColumn), ColumnKind.Label, 0);
                    for (int j = numberOfDataColumnsChangeToPropertyColumns, k = 0; j < srcTable.DataColumnCount; ++j, ++k)
                    {
                        destCol[k] = srcTable.DataColumns.GetColumnName(j);
                    }
                }

                int numberOfExtraPriorDestColumns = (options.StoreDataColumnNamesInFirstDataColumn ? 1 : 0);

                // 1st, copy the property columns to data columns
                for (int i = 0; i < numberOfPropertyColumnsChangeToDataColumns; ++i)
                {
                    var destCol = destTable.DataColumns.EnsureExistenceAtPositionStrictly(i + numberOfExtraPriorDestColumns, srcTable.PropertyColumns.GetColumnName(i), srcTable.PropertyColumns[i].GetType(), srcTable.PropertyColumns.GetColumnKind(i), srcTable.PropertyColumns.GetColumnGroup(i));
                    var srcCol  = srcTable.PropertyColumns[i];
                    for (int j = numberOfDataColumnsChangeToPropertyColumns, k = 0; j < srcCol.Count; ++j, ++k)
                    {
                        destCol[k] = srcCol[j];
                    }
                }

                // 2rd, transpose the data columns
                int srcRows = 0;
                foreach (int i in dataColumnsToTransposeIndices)
                {
                    srcRows = Math.Max(srcRows, srcTable.DataColumns[i].Count);
                }

                // create as many columns in destTable as srcRows and fill them with data
                Type columnType = dataColumnsToTransposeIndices.Count > 0 ? srcTable.DataColumns[dataColumnsToTransposeIndices[0]].GetType() : null;
                for (int i = 0; i < srcRows; ++i)
                {
                    string destColName = string.Format("{0}{1}", options.ColumnNamingPreString, i);
                    if (options.UseFirstDataColumnForColumnNaming)
                    {
                        destColName = string.Format("{0}{1}", options.ColumnNamingPreString, srcTable.DataColumns[0][i]);
                    }

                    var destCol = destTable.DataColumns.EnsureExistenceAtPositionStrictly(numberOfPriorDestDataColumns + i, destColName, false, columnType, ColumnKind.V, 0);
                    int k       = 0;
                    foreach (int j in dataColumnsToTransposeIndices)
                    {
                        destCol[k++] = srcTable.DataColumns[j][i];
                    }
                }

                // 3rd, copy the first data columns to property columns
                for (int i = 0; i < numberOfDataColumnsChangeToPropertyColumns; ++i)
                {
                    var destCol = destTable.PropertyColumns.EnsureExistenceAtPositionStrictly(i, srcTable.DataColumns.GetColumnName(i), srcTable.DataColumns[i].GetType(), srcTable.DataColumns.GetColumnKind(i), srcTable.DataColumns.GetColumnGroup(i));
                    var srcCol  = srcTable.DataColumns[i];
                    for (int j = numberOfPriorDestDataColumns, k = 0; k < srcCol.Count; ++j, ++k)
                    {
                        destCol[j] = srcCol[k];
                    }
                }

                // 4th, fill the rest of the property columns with the rest of the data columns
                for (int i = 0; i < numberOfDataColumnsChangeToPropertyColumns; ++i)
                {
                    for (int j = 0; j < numberOfPropertyColumnsChangeToDataColumns; ++j)
                    {
                        try
                        {
                            destTable.PropertyColumns[i][j + numberOfExtraPriorDestColumns] = srcTable.PropertyColumns[j][i];
                        }
                        catch { }
                    }
                }

                // and 5th, copy the remaining property columns to property columns
                for (int i = numberOfPropertyColumnsChangeToDataColumns, j = numberOfDataColumnsChangeToPropertyColumns; i < srcTable.PropertyColumns.ColumnCount; ++i, ++j)
                {
                    var destCol = destTable.PropertyColumns.EnsureExistenceAtPositionStrictly(j, srcTable.PropertyColumns.GetColumnName(i), false, srcTable.PropertyColumns[i].GetType(), srcTable.PropertyColumns.GetColumnKind(i), srcTable.DataColumns.GetColumnGroup(i));
                    destCol.Data = srcTable.PropertyColumns[i];
                }

                suspendToken.Resume();
            }
        }
Beispiel #11
0
        /// <summary>
        /// Remove the selected columns, rows or property columns.
        /// </summary>
        public static void RemoveSelected(IWorksheetController ctrl)
        {
            using (var suspendToken = ctrl.DataTable.SuspendGetToken())
            {
                // Property columns are only deleted, if selected alone or in conjunction with data row selection
                if (ctrl.SelectedPropertyColumns.Count > 0 && ctrl.SelectedPropertyRows.Count == 0 && ctrl.SelectedDataColumns.Count == 0)
                {
                    ctrl.DataTable.PropCols.RemoveColumns(ctrl.SelectedPropertyColumns);
                    ctrl.SelectedPropertyColumns.Clear();
                    ctrl.SelectedPropertyRows.Clear();
                }
                // note here: Property rows are only removed indirect by removing data columns

                // delete the selected columns if there are _only selected columns
                if (ctrl.SelectedDataColumns.Count > 0 && ctrl.SelectedDataRows.Count == 0)
                {
                    ctrl.DataTable.RemoveColumns(ctrl.SelectedDataColumns);
                    ctrl.SelectedDataColumns.Clear(); // now the columns are deleted, so they cannot be selected
                }

                // if rows are selected, remove them in all selected columns or in all columns (if no column selection=
                if (ctrl.SelectedDataRows.Count > 0)
                {
                    ctrl.DataTable.DataColumns.RemoveRowsInColumns(
                        ctrl.SelectedDataColumns.Count > 0 ? (IAscendingIntegerCollection)ctrl.SelectedDataColumns : ContiguousIntegerRange.FromStartAndCount(0, ctrl.DataTable.DataColumns.ColumnCount),
                        ctrl.SelectedDataRows);

                    ctrl.SelectedDataColumns.Clear();
                    ctrl.SelectedDataRows.Clear();
                }

                // end code for the selected rows
                suspendToken.Dispose();
            }

            ctrl.TableAreaInvalidate(); // necessary because we changed the selections
        }
Beispiel #12
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DataTableMultipleColumnProxy"/> class. The selected collections determine which columns and rows contribute to this instance.
        /// The group number is determined by the first selected column (or, if no column is selected, by the first column of the data table).
        /// </summary>
        /// <param name="identifier">The identifier of the bundle of columns that are initially set with this constructor.</param>
        /// <param name="table">The underlying table.</param>
        /// <param name="selectedDataRows">The selected data rows.</param>
        /// <param name="selectedDataColumns">The selected data columns.</param>
        /// <exception cref="System.ArgumentNullException">table must not be null.</exception>
        public DataTableMultipleColumnProxy(string identifier, DataTable table, IAscendingIntegerCollection selectedDataRows, IAscendingIntegerCollection selectedDataColumns)
        {
            if (null == identifier)
            {
                throw new ArgumentNullException("identifier");
            }

            if (null == table)
            {
                throw new ArgumentNullException("table");
            }

            _dataColumnBundles = new Dictionary <string, ColumnBundleInfo>();

            _dataTable = new DataTableProxy(table)
            {
                ParentObject = this
            };

            _groupNumber = 0;

            if (null != selectedDataColumns && selectedDataColumns.Count > 0)
            {
                _groupNumber = table.DataColumns.GetColumnGroup(table[selectedDataColumns[0]]);
            }

            var bundle = new ColumnBundleInfo();

            _dataColumnBundles.Add(identifier, bundle);

            int maxRowCount = 0;

            if (selectedDataColumns != null && selectedDataColumns.Count > 0)
            {
                for (int i = 0; i < selectedDataColumns.Count; ++i)
                {
                    var col = table[selectedDataColumns[i]];
                    if (table.DataColumns.GetColumnGroup(col) == _groupNumber)
                    {
                        InternalAddDataColumnNoClone(bundle, ReadableColumnProxyBase.FromColumn(col));
                        maxRowCount = Math.Max(maxRowCount, col.Count);
                    }
                }
            }
            else // nothing selected - use all columns of group number 0
            {
                for (int i = 0; i < table.DataColumnCount; ++i)
                {
                    var col = table[i];
                    if (table.DataColumns.GetColumnGroup(col) == _groupNumber)
                    {
                        InternalAddDataColumnNoClone(bundle, ReadableColumnProxyBase.FromColumn(col));
                        maxRowCount = Math.Max(maxRowCount, col.Count);
                    }
                }
            }

            _useAllAvailableDataRows = null == selectedDataRows || selectedDataRows.Count == 0;

            _participatingDataRows = new AscendingIntegerCollection(_useAllAvailableDataRows ? ContiguousIntegerRange.FromStartAndCount(0, maxRowCount) : selectedDataRows);
        }
		/// <summary>
		/// Get the next range (i.e. a contiguous range of integers) in descending order.
		/// </summary>
		/// <param name="currentposition">The current position into this collection. Use Count-1 for the first time. On return, this is the next position.</param>
		/// <param name="result">Returns the next contiguous interger range if the return value is <c>true</c>.</param>
		/// <returns>True if the range data are valid, false if there is no more data. Used as end-of-loop indicator.</returns>
		/// <remarks>You can use this function in a while loop:
		/// <code>
		/// int rangestart, rangecount;
		/// int currentPosition=selection.Count-1;
		/// while(selection.GetNextRangeAscending(currentPosition,out rangestart, out rangecount))
		///   {
		///   // do your things here
		///   }
		/// </code></remarks>
		public bool GetNextRangeDescending(ref int currentposition, out ContiguousIntegerRange result)
		{
			int rangestart, rangecount;
			if (currentposition < 0 || currentposition >= Count)
			{
				result = ContiguousIntegerRange.Empty;
				return false;
			}
			else
			{
				rangestart = this[currentposition];
				rangecount = 1;
				for (currentposition = currentposition - 1; currentposition >= 0; currentposition--)
				{
					if (this[currentposition] == (rangestart - 1))
					{
						rangestart--;
						rangecount++;
					}
					else
					{
						break;
					}
				}

				result = ContiguousIntegerRange.FromStartAndCount(rangestart, rangecount);
				return true;
			}
		}
		/// <summary>
		/// Get the next range (i.e. a contiguous range of integers) in ascending order.
		/// </summary>
		/// <param name="currentposition">The current position into this collection. Use 0 for the first time. On return, this is the next position.</param>
		/// <param name="result">Returns the next contiguous range if the return value is <c>true</c>.</param>
		/// <returns>True if the returned data are valid, false if there is no more data.</returns>
		/// <remarks>You can use this function in a while loop:
		/// <code>
		/// int rangestart, rangecount;
		/// int currentPosition=0;
		/// while(GetNextRangeAscending(ref currentPosition, out rangestart, out rangecount))
		///   {
		///   // do your things here
		///   }
		/// </code></remarks>
		public bool GetNextRangeAscending(ref int currentposition, out ContiguousIntegerRange result)
		{
			int rangestart;
			int rangecount;

			if (currentposition < 0 || currentposition >= Count)
			{
				result = ContiguousIntegerRange.Empty;
				return false;
			}
			else
			{
				rangestart = this[currentposition];
				int previous = rangestart;
				rangecount = 1;
				for (currentposition = currentposition + 1; currentposition < Count; currentposition++)
				{
					if (this[currentposition] == (previous + 1))
					{
						previous++;
						rangecount++;
					}
					else
					{
						break;
					}
				}

				result = ContiguousIntegerRange.FromStartAndCount(rangestart, rangecount);
				return true;
			}
		}
		/// <summary>
		/// Finds the source row for a given value inside a given row range.
		/// </summary>
		/// <param name="srcXCol">Column where the value must be found.</param>
		/// <param name="xVal">Value to find.</param>
		/// <param name="range">Range of rows.</param>
		/// <returns>The row for which the element is equal to the value, or -1 if the value could not be found.</returns>
		private static int FindSrcXRow(DataColumn srcXCol, AltaxoVariant xVal, ContiguousIntegerRange range)
		{
			// Find the src row
			foreach (int idx in range)
				if (srcXCol[idx] == xVal)
					return idx;
			return -1;
		}