diff --git a/src/Microsoft.Data.Analysis/DataFrameColumn.cs b/src/Microsoft.Data.Analysis/DataFrameColumn.cs index 2f7fae57b4..f414051b31 100644 --- a/src/Microsoft.Data.Analysis/DataFrameColumn.cs +++ b/src/Microsoft.Data.Analysis/DataFrameColumn.cs @@ -212,7 +212,9 @@ public object this[long rowIndex] /// /// Clones the column. /// - /// The number of null values to append to the copied values. + /// + /// The number of null values to append to the copied values. Columns that do not support null values append default values instead. + /// /// A new public DataFrameColumn Clone(long numberOfNullsToAppend = 0) => CloneImplementation(numberOfNullsToAppend); @@ -229,7 +231,9 @@ public object this[long rowIndex] /// to process integer values in in reverse order; /// otherwise, . This parameter does not affect a Boolean map. /// - /// The number of null values to append after the selected values. + /// + /// The number of null values to append after the selected values. Columns that do not support null values append default values instead. + /// /// A new public DataFrameColumn Clone(DataFrameColumn mapIndices, bool invertMapIndices = false, long numberOfNullsToAppend = 0) => CloneImplementation(mapIndices, invertMapIndices, numberOfNullsToAppend); diff --git a/src/Microsoft.Data.Analysis/DataFrameColumns/VBufferDataFrameColumn.cs b/src/Microsoft.Data.Analysis/DataFrameColumns/VBufferDataFrameColumn.cs index b86c6d6367..a32d5f4b96 100644 --- a/src/Microsoft.Data.Analysis/DataFrameColumns/VBufferDataFrameColumn.cs +++ b/src/Microsoft.Data.Analysis/DataFrameColumns/VBufferDataFrameColumn.cs @@ -267,13 +267,35 @@ private VBufferDataFrameColumn CloneImplementation(PrimitiveDataFrameColumn + /// + /// Clones the column, selecting and ordering values according to . + /// + /// + /// A Boolean, , or column that determines which values to copy. + /// For a Boolean column, the value at each position selects the value at the same position when it is + /// . For an integer column, each value is a zero-based index into this column; + /// the map order determines the result order, and repeated indices produce repeated values. + /// + /// + /// to process integer values in in reverse order; + /// otherwise, . This parameter does not affect a Boolean map. + /// + /// + /// The number of default values to append after the selected values. + /// + /// A new . public new VBufferDataFrameColumn Clone(DataFrameColumn mapIndices, bool invertMapIndices, long numberOfNullsToAppend) { return (VBufferDataFrameColumn)CloneImplementation(mapIndices, invertMapIndices, numberOfNullsToAppend); } - /// + /// + /// Clones the column. + /// + /// + /// The number of default values to append to the copied values. + /// + /// A new . public new VBufferDataFrameColumn Clone(long numberOfNullsToAppend = 0) { return (VBufferDataFrameColumn)CloneImplementation(numberOfNullsToAppend); @@ -299,6 +321,9 @@ protected override DataFrameColumn CloneImplementation(DataFrameColumn mapIndice clone = Clone(); } + for (long i = 0; i < numberOfNullsToAppend; i++) + clone.Append(default); + return clone; } @@ -309,6 +334,9 @@ protected override DataFrameColumn CloneImplementation(long numberOfNullsToAppen for (long i = 0; i < Length; i++) ret[i] = this[i]; + for (long i = 0; i < numberOfNullsToAppend; i++) + ret.Append(default); + return ret; } diff --git a/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumn.cs b/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumn.cs index 696a0d0b6d..a41c917d90 100644 --- a/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumn.cs +++ b/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumn.cs @@ -547,14 +547,10 @@ public PrimitiveDataFrameColumn Clone(PrimitiveDataFrameColumn mapIndice /// A new . public PrimitiveDataFrameColumn Clone(IEnumerable mapIndices) { - IEnumerator rows = mapIndices.GetEnumerator(); PrimitiveDataFrameColumn ret = CreateNewColumn(Name); - long numberOfRows = 0; - while (rows.MoveNext() && numberOfRows < Length) + foreach (long rowIndex in mapIndices) { - numberOfRows++; - var curRow = rows.Current; - var value = _columnContainer[curRow]; + var value = _columnContainer[rowIndex]; ret.Append(value); } return ret; diff --git a/test/Microsoft.Data.Analysis.Tests/PrimitiveDataFrameColumnTests.cs b/test/Microsoft.Data.Analysis.Tests/PrimitiveDataFrameColumnTests.cs index 0111a7a316..b15caf9b22 100644 --- a/test/Microsoft.Data.Analysis.Tests/PrimitiveDataFrameColumnTests.cs +++ b/test/Microsoft.Data.Analysis.Tests/PrimitiveDataFrameColumnTests.cs @@ -439,6 +439,20 @@ public void TestNotNullableColumnCloneWithIndicesMapAsEnumerableInt() Assert.Equal(column[indicesMap[i]], clonedColumn[i]); } + [Fact] + public void TestColumnCloneWithEnumerableIndicesLongerThanColumn() + { + var column = new Int32DataFrameColumn("Int column", values: new[] { 10, 20 }); + var longIndicesMap = new long[] { 0, 1, 0 }; + var intIndicesMap = new int[] { 1, 0, 1 }; + + PrimitiveDataFrameColumn longIndicesClone = column.Clone(longIndicesMap); + PrimitiveDataFrameColumn intIndicesClone = column.Clone(intIndicesMap); + + Assert.Equal(new int?[] { 10, 20, 10 }, longIndicesClone); + Assert.Equal(new int?[] { 20, 10, 20 }, intIndicesClone); + } + [Fact] public void TestNullableColumnCloneWithIndicesMapAndSmallerSize() { diff --git a/test/Microsoft.Data.Analysis.Tests/VBufferColumnTests.cs b/test/Microsoft.Data.Analysis.Tests/VBufferColumnTests.cs index e84b324987..cb11a5005b 100644 --- a/test/Microsoft.Data.Analysis.Tests/VBufferColumnTests.cs +++ b/test/Microsoft.Data.Analysis.Tests/VBufferColumnTests.cs @@ -46,6 +46,29 @@ public void TestVBufferColumn_Indexer() Assert.Equal(0, vBufferColumn[0].GetValues()[4]); } + [Fact] + public void TestVBufferColumn_CloneAppendsDefaultValues() + { + var first = new VBuffer(2, new[] { 1, 2 }); + var second = new VBuffer(2, new[] { 3, 4 }); + var column = new VBufferDataFrameColumn("VBuffer", new[] { first, second }); + var mapIndices = new Int32DataFrameColumn("Indices", new[] { 1 }); + + VBufferDataFrameColumn clone = column.Clone(numberOfNullsToAppend: 2); + VBufferDataFrameColumn mappedClone = column.Clone(mapIndices, invertMapIndices: false, numberOfNullsToAppend: 2); + + Assert.Equal(4, clone.Length); + Assert.Equal(first.GetValues().ToArray(), clone[0].GetValues().ToArray()); + Assert.Equal(second.GetValues().ToArray(), clone[1].GetValues().ToArray()); + Assert.Equal(0, clone[2].GetValues().Length); + Assert.Equal(0, clone[3].GetValues().Length); + + Assert.Equal(3, mappedClone.Length); + Assert.Equal(second.GetValues().ToArray(), mappedClone[0].GetValues().ToArray()); + Assert.Equal(0, mappedClone[1].GetValues().Length); + Assert.Equal(0, mappedClone[2].GetValues().Length); + } + [X64Fact("32-bit doesn't allow to allocate more than 2 Gb")] public void TestVBufferColumn_Indexer_MoreThanMaxInt() {