Skip to content

Commit d76a2d3

Browse files
committed
Move column type checks out of comparator to improve performance
1 parent 17f5a59 commit d76a2d3

File tree

1 file changed

+35
-66
lines changed

1 file changed

+35
-66
lines changed

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/KotlinNotebookPluginUtils.kt

Lines changed: 35 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -105,86 +105,54 @@ public object KotlinNotebookPluginUtils {
105105
ColumnPath(path)
106106
}
107107

108-
val comparator = createComparator(sortKeys, isDesc)
108+
val comparator = createComparator(df, sortKeys, isDesc)
109109

110110
return df.sortWith(comparator)
111111
}
112112

113-
private fun createComparator(sortKeys: List<ColumnPath>, isDesc: List<Boolean>): Comparator<DataRow<*>> {
114-
return Comparator { row1, row2 ->
115-
for ((key, desc) in sortKeys.zip(isDesc)) {
116-
val column = row1.df().getColumn(key)
117-
val comparisonResult = if (column.valuesAreComparable()) {
118-
compareComparableValues(row1, row2, key, desc)
119-
} else if (column.isFrameColumn()) {
120-
val firstValue = column[row1].rowsCount()
121-
val secondValue = column[row2].rowsCount()
122-
firstValue.compare(secondValue, desc)
123-
} else if (column.isList()) {
124-
compareListSizes(row1, row2, key, desc)
125-
} else {
126-
compareStringValues(row1, row2, key, desc)
113+
private fun createComparator(
114+
df: AnyFrame,
115+
sortKeys: List<ColumnPath>,
116+
isDesc: List<Boolean>,
117+
): Comparator<DataRow<*>> {
118+
val columnComparators = sortKeys.zip(isDesc).map { (key, desc) ->
119+
val column = df.getColumn(key)
120+
createColumnComparator(column, desc)
121+
}
122+
123+
return when (columnComparators.size) {
124+
1 -> columnComparators.single()
125+
126+
else -> Comparator { row1, row2 ->
127+
for (comparator in columnComparators) {
128+
val result = comparator.compare(row1, row2)
129+
// If a comparison result is non-zero, we have resolved the ordering
130+
if (result != 0) return@Comparator result
127131
}
128-
// If a comparison result is non-zero, we have resolved the ordering
129-
if (comparisonResult != 0) return@Comparator comparisonResult
132+
// All comparisons are equal
133+
0
130134
}
131-
// All comparisons are equal
132-
0
133135
}
134136
}
135137

136-
private fun compareListSizes(
137-
row1: DataRow<*>,
138-
row2: DataRow<*>,
139-
key: ColumnPath,
140-
desc: Boolean,
141-
): Int {
142-
val firstValue = (row1.getValueOrNull(key) as? List<*>)?.size ?: 0
143-
val secondValue = (row2.getValueOrNull(key) as? List<*>)?.size ?: 0
144-
return if (desc) {
145-
secondValue.compareTo(firstValue)
146-
} else {
147-
firstValue.compareTo(secondValue)
148-
}
149-
}
138+
private fun createColumnComparator(column: AnyCol, desc: Boolean): Comparator<DataRow<*>> {
139+
val comparator: Comparator<DataRow<*>> = when {
140+
column.valuesAreComparable() -> compareBy(nullsLast()) {
141+
column[it] as Comparable<Any?>?
142+
}
150143

151-
@Suppress("UNCHECKED_CAST")
152-
private fun compareComparableValues(
153-
row1: DataRow<*>,
154-
row2: DataRow<*>,
155-
key: ColumnPath,
156-
desc: Boolean,
157-
): Int {
158-
val firstValue = row1.getValueOrNull(key) as Comparable<Any?>?
159-
val secondValue = row2.getValueOrNull(key) as Comparable<Any?>?
160-
161-
return when {
162-
firstValue == null && secondValue == null -> 0
163-
firstValue == null -> if (desc) 1 else -1
164-
secondValue == null -> if (desc) -1 else 1
165-
desc -> secondValue.compareTo(firstValue)
166-
else -> firstValue.compareTo(secondValue)
167-
}
168-
}
144+
// Comparator shows a slight improvement in performance for this case
145+
column.isFrameColumn() -> Comparator { r1, r2 ->
146+
column[r1].rowsCount().compareTo(column[r2].rowsCount())
147+
}
148+
149+
column.isList() -> compareBy { (column[it] as? List<*>)?.size ?: 0 }
169150

170-
private fun compareStringValues(
171-
row1: DataRow<*>,
172-
row2: DataRow<*>,
173-
key: ColumnPath,
174-
desc: Boolean,
175-
): Int {
176-
val firstValue = (row1.getValueOrNull(key)?.toString() ?: "")
177-
val secondValue = (row2.getValueOrNull(key)?.toString() ?: "")
178-
179-
return if (desc) {
180-
secondValue.compareTo(firstValue)
181-
} else {
182-
firstValue.compareTo(secondValue)
151+
else -> compareBy { column[it]?.toString() ?: "" }
183152
}
153+
return if (desc) comparator.reversed() else comparator
184154
}
185155

186-
private fun <T : Comparable<T>> T.compare(other: T, desc: Boolean) = if (desc) other.compareTo(this) else this.compareTo(other)
187-
188156
internal fun isDataframeConvertable(dataframeLike: Any?): Boolean =
189157
when (dataframeLike) {
190158
is Pivot<*>,
@@ -262,6 +230,7 @@ public object KotlinNotebookPluginUtils {
262230

263231
is FormattedFrame<*> -> dataframeLike.df
264232

233+
// мб повыше перенести
265234
is AnyFrame -> dataframeLike
266235

267236
is AnyRow -> dataframeLike.toDataFrame()

0 commit comments

Comments
 (0)