@@ -3,6 +3,7 @@ package org.jetbrains.kotlinx.dataframe.jupyter
33import org.jetbrains.kotlinx.dataframe.AnyCol
44import org.jetbrains.kotlinx.dataframe.AnyFrame
55import org.jetbrains.kotlinx.dataframe.AnyRow
6+ import org.jetbrains.kotlinx.dataframe.DataFrame
67import org.jetbrains.kotlinx.dataframe.DataRow
78import org.jetbrains.kotlinx.dataframe.annotations.RequiredByIntellijPlugin
89import org.jetbrains.kotlinx.dataframe.api.Convert
@@ -29,15 +30,17 @@ import org.jetbrains.kotlinx.dataframe.api.at
2930import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
3031import org.jetbrains.kotlinx.dataframe.api.frames
3132import org.jetbrains.kotlinx.dataframe.api.getColumn
33+ import org.jetbrains.kotlinx.dataframe.api.getRows
3234import org.jetbrains.kotlinx.dataframe.api.into
3335import org.jetbrains.kotlinx.dataframe.api.isFrameColumn
3436import org.jetbrains.kotlinx.dataframe.api.isList
35- import org.jetbrains.kotlinx.dataframe.api.sortWith
37+ import org.jetbrains.kotlinx.dataframe.api.rows
3638import org.jetbrains.kotlinx.dataframe.api.toDataFrame
3739import org.jetbrains.kotlinx.dataframe.api.values
3840import org.jetbrains.kotlinx.dataframe.api.valuesAreComparable
3941import org.jetbrains.kotlinx.dataframe.columns.ColumnPath
4042import org.jetbrains.kotlinx.dataframe.impl.ColumnNameGenerator
43+ import java.util.Arrays
4144
4245/* *
4346 * A class with utility methods for Kotlin Notebook Plugin integration.
@@ -105,9 +108,34 @@ public object KotlinNotebookPluginUtils {
105108 ColumnPath (path)
106109 }
107110
111+ if (sortKeys.size == 1 ) {
112+ val column = df.getColumn(sortKeys[0 ])
113+
114+ // Not sure how to have generic logic that would produce Comparator<Int> and Comparator<DataRow> without overhead
115+ // For now Comparator<DataRow> is needed for fallback case of sorting multiple columns. Although it's now impossible in UI
116+ // Please make sure to change both this and createColumnComparator
117+ val comparator: Comparator <Int > = when {
118+ column.valuesAreComparable() -> compareBy(nullsLast()) {
119+ column[it] as Comparable <Any >?
120+ }
121+
122+ column.isFrameColumn() -> compareBy { column[it].rowsCount() }
123+
124+ column.isList() -> compareBy { (column[it] as ? List <* >)?.size ? : 0 }
125+
126+ else -> compareBy { column[it]?.toString() ? : " " }
127+ }
128+
129+ val finalComparator = if (isDesc[0 ]) comparator.reversed() else comparator
130+
131+ val permutation = Array (column.size()) { it }
132+ Arrays .parallelSort(permutation, finalComparator)
133+ return SortedDataFrameView (df, permutation.asList())
134+ }
135+
108136 val comparator = createComparator(df, sortKeys, isDesc)
109137
110- return df.sortWith (comparator)
138+ return df.sortWithLazy (comparator)
111139 }
112140
113141 private fun createComparator (
@@ -153,6 +181,27 @@ public object KotlinNotebookPluginUtils {
153181 return if (desc) comparator.reversed() else comparator
154182 }
155183
184+ private fun <T > DataFrame<T>.sortWithLazy (comparator : Comparator <DataRow <T >>): DataFrame <T > {
185+ val permutation = rows().sortedWith(comparator).map { it.index() }
186+ return SortedDataFrameView (this , permutation)
187+ }
188+
189+ private class SortedDataFrameView <T >(private val source : DataFrame <T >, private val permutation : List <Int >) :
190+ DataFrame <T > by source {
191+
192+ override operator fun get (index : Int ): DataRow <T > = source[permutation[index]]
193+
194+ override operator fun get (range : IntRange ): DataFrame <T > {
195+ val indices = range.map { permutation[it] }
196+ return source.getRows(indices)
197+ }
198+
199+ override operator fun get (indices : Iterable <Int >): DataFrame <T > {
200+ val mappedIndices = indices.map { permutation[it] }
201+ return source.getRows(mappedIndices)
202+ }
203+ }
204+
156205 internal fun isDataframeConvertable (dataframeLike : Any? ): Boolean =
157206 when (dataframeLike) {
158207 is Pivot <* >,
0 commit comments