Skip to content

Commit 3f3a97b

Browse files
Merge pull request #1 from shmueldabomb441/replace-sort-with-delegate
Update KotlinFunctionLibrary.kt
2 parents 1927609 + 294ba78 commit 3f3a97b

1 file changed

Lines changed: 65 additions & 219 deletions

File tree

src/main/kotlin/KotlinFunctionLibrary.kt

Lines changed: 65 additions & 219 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import kotlin.reflect.KProperty1
1616
import kotlin.reflect.full.memberProperties
1717
import kotlin.reflect.full.primaryConstructor
1818
import kotlin.system.measureNanoTime
19+
import SortingDelegate.sort as sortFromDelegate
1920

2021

2122
/**
@@ -33,7 +34,7 @@ object KotlinFunctionLibrary {
3334
* */
3435
val <T : Any> KClass<T>.parameters: List<String?>?
3536
get() {
36-
return primaryConstructor?.parameters?.toListBy { it.name }?.toList()
37+
return primaryConstructor?.parameters?.map { it.name }?.toList()
3738
}
3839

3940
/**
@@ -54,6 +55,68 @@ object KotlinFunctionLibrary {
5455
randomListOfWords
5556
}
5657

58+
/**
59+
* Sorts a list by mutliple criteria
60+
* NOTE: mutates the provided list in the process
61+
* @sample sort(
62+
* myList,
63+
* listOf(Class::myParameter1.name, Class::myParameter2.name),
64+
* listOf(true, false)
65+
* )
66+
*/
67+
@JvmName("sortWithListGivenAsParameters")
68+
inline fun <reified T> sort(
69+
workingList: MutableList<T>,
70+
sortCriteria: List<String>,
71+
ascending: List<Boolean>
72+
) = sortFromDelegate(workingList, sortCriteria, ascending)
73+
/**
74+
*
75+
* much faster than passing in sort criteria strings
76+
* @sample sort(
77+
* myList,
78+
* listOf(
79+
* Class::myParameter1 as KProperty1<Class, Comparable<Any>>,
80+
* Class::myParameter2 as KProperty1<Class, Comparable<Any>>
81+
* ),
82+
* listOf(true, false)
83+
* )
84+
* */
85+
inline fun <reified T> sort(
86+
workingList: MutableList<T>,
87+
sortCriteria: List<KProperty1<T, Comparable<Any>?>>,
88+
ascending: List<Boolean>
89+
) = sortFromDelegate(workingList, sortCriteria, ascending)
90+
/**
91+
* Wrapper to {@link sort(MutableList<T>,List<KProperty1<T, Comparable<Any>?>>,List<Boolean>)} using [Map] for a more convenient API
92+
* */
93+
inline fun <reified T> sort(
94+
workingList: MutableList<T>,
95+
sortCriteriaMappedToAscending: Map<KProperty1<T, Comparable<Any>?>, Boolean>
96+
) = sortFromDelegate(workingList, sortCriteriaMappedToAscending)
97+
/**
98+
* Wrapper to {@link sort(MutableList<T>,List<String>,List<Boolean>)} using [Map] for a more convenient API
99+
* */
100+
@JvmName("sortWithClassParameterStrings")
101+
inline fun <reified T> sort(
102+
workingList: MutableList<T>,
103+
sortCriteriaMappedToAscending: Map<String, Boolean>
104+
) = sortFromDelegate(workingList, sortCriteriaMappedToAscending)
105+
/**
106+
* Wrapper to {@link sort(MutableList<T>,List<KProperty1<T, Comparable<Any>?>>,List<Boolean>)} using [Map] for a more convenient API
107+
* */
108+
@JvmName("sortWithListAsReceiverAndMapOfKProperty1")
109+
inline fun <reified T> MutableList<T>.sort(
110+
map: Map<KProperty1<T, Comparable<Any>?>, Boolean>
111+
) = sortFromDelegate(map)
112+
/**
113+
* Wrapper to {@link sort(MutableList<T>,List<String>,List<Boolean>)} using [Map] for a more convenient API
114+
* */
115+
@JvmName("sortWithListAsReceiverAndMapOfString")
116+
inline fun <reified T> MutableList<T>.sort(
117+
map: Map<String, Boolean>
118+
) = sortFromDelegate(map)
119+
57120
/**
58121
* A version of print which prints [this] and returns [this], facilitating fluent interfaces, functional programming, and assisting in debugging.
59122
* Also useful for debugging values without breaking a call change or interrupting the flow of code for logging values.
@@ -306,223 +369,6 @@ object KotlinFunctionLibrary {
306369
minute1 %= 60
307370
return Triple(hour1, minute1, second1)
308371
}
309-
310-
/**
311-
* Sorts a list by mutliple criteria
312-
* NOTE: mutates the provided list in the process
313-
* @sample sort(
314-
myList,
315-
listOf(Class::myParameter1.name, Class::myParameter2.name),
316-
listOf(true, false)
317-
)
318-
*/
319-
@JvmName("sortWithListGivenAsParameters")
320-
inline fun <reified T> sort(
321-
workingList: MutableList<T>,
322-
sortCriteria: List<String>,
323-
ascending: List<Boolean>
324-
) {
325-
/*//unoptimized version:
326-
val oneOfMyClasses = workingList[0]::class
327-
val firstSelector = oneOfMyClasses.getPropertyToSortBy(shiurFilterOptions[0])
328-
val compareBy = getComparator(ascending, firstSelector, shiurFilterOptions, oneOfMyClasses)
329-
workingList.sortWith(compareBy)*/
330-
//optimized version:
331-
332-
val size = requireNotEmptyAndSameSize(
333-
ascending, sortCriteria, "List of ascending/descending must not be empty",
334-
"List of sort criteria must not be empty",
335-
"Each sort criteria must be matched with a ascending/descending boolean; size of ascending/descending list: %d, Size of sort criteria list: %d "
336-
)
337-
338-
workingList.sortWith(
339-
PRIVATEgetComparator(
340-
ascending,
341-
PRIVATEgetPropertyToSortBy(sortCriteria[0]),
342-
sortCriteria,
343-
size.second
344-
)
345-
)
346-
347-
}
348-
349-
/**
350-
*
351-
* much faster than passing in sort criteria strings
352-
* * @sample sort(
353-
myList,
354-
listOf(Class::myParameter1 as KProperty1<Class, Comparable<Any>>,
355-
Class::myParameter2 as KProperty1<Class, Comparable<Any>>),
356-
listOf(true, false)
357-
)
358-
* */
359-
inline fun <reified T> sort(
360-
workingList: MutableList<T>,
361-
sortCriteria: List<KProperty1<T, Comparable<Any>?>>,
362-
ascending: List<Boolean>
363-
) {
364-
val size = requireNotEmptyAndSameSize(
365-
ascending, sortCriteria, "List of ascending/descending must not be empty",
366-
"List of sort criteria must not be empty",
367-
"Each sort criteria must be matched with a ascending/descending boolean; size of ascending/descending list: %d, Size of sort criteria list: %d "
368-
)
369-
workingList.sortWith(
370-
PRIVATEgetComparator(
371-
ascending,
372-
sortCriteria[0],
373-
sortCriteria,
374-
size.second
375-
)
376-
)
377-
}
378-
379-
/**
380-
* Wrapper to {@link sort(MutableList<T>,List<KProperty1<T, Comparable<Any>?>>,List<Boolean>)} using [Map] for a more convenient API
381-
* */
382-
inline fun <reified T> sort(
383-
workingList: MutableList<T>,
384-
sortCriteriaMappedToAscending: Map<KProperty1<T, Comparable<Any>?>, Boolean>
385-
) = sort(workingList, sortCriteriaMappedToAscending.keys.toList(), sortCriteriaMappedToAscending.values.toList())
386-
387-
/**
388-
* Wrapper to {@link sort(MutableList<T>,List<String>,List<Boolean>)} using [Map] for a more convenient API
389-
* */
390-
@JvmName("sortWithClassParameterStrings")
391-
inline fun <reified T> sort(
392-
workingList: MutableList<T>,
393-
sortCriteriaMappedToAscending: Map<String, Boolean>
394-
) = sort(
395-
workingList,
396-
sortCriteriaMappedToAscending.keys.toMutableList(),
397-
sortCriteriaMappedToAscending.values.toList()
398-
)
399-
400-
/**
401-
* Wrapper to {@link sort(MutableList<T>,List<KProperty1<T, Comparable<Any>?>>,List<Boolean>)} using [Map] for a more convenient API
402-
* */
403-
@JvmName("sortWithListAsReceiverAndMapOfKProperty1")
404-
inline fun <reified T> MutableList<T>.sort(
405-
map: Map<KProperty1<T, Comparable<Any>?>, Boolean>
406-
) = sort(this, map.keys.toList(), map.values.toList())
407-
408-
/**
409-
* Wrapper to {@link sort(MutableList<T>,List<String>,List<Boolean>)} using [Map] for a more convenient API
410-
* */
411-
@JvmName("sortWithListAsReceiverAndMapOfString")
412-
inline fun <reified T> MutableList<T>.sort(
413-
map: Map<String, Boolean>
414-
) = sort(this, map.keys.toMutableList(), map.values.toList())
415-
416-
/**
417-
* Takes two lists and throws an [IllegalArgumentException] if either of the lists are empty or if they are different sizes.
418-
* @param aEmptyMessage message to be printed if [listA] is empty; optionally use "%d" as a template/placeholder for the size of [listA]
419-
* @param bEmptyMessage message to be printed if [listB] is empty; optionally use "%d" as a template/placeholder for the size of [listB]
420-
* @param notSameSizeMessage message to br printed if lists are not the same size; optionally use the first "%d" as a template/placeholder for the size of [listB]
421-
* @return a [Pair] of [listA].size, [listB].size
422-
* */
423-
fun <A, B> requireNotEmptyAndSameSize(
424-
listA: Collection<A>, //ascending
425-
listB: Collection<B>, //sortCriteria
426-
aEmptyMessage: String = "List A is empty.",
427-
bEmptyMessage: String = "List B is empty.",
428-
notSameSizeMessage: String = "Lists are not same size; List A is size %d, List B is size %d."
429-
): Pair<Int, Int> {
430-
val sizeA = listA.size
431-
val sizeB = listB.size
432-
require(sizeA > 0) { System.out.printf(aEmptyMessage, sizeA) }
433-
require(sizeB > 0) { System.out.printf(bEmptyMessage, sizeB) }
434-
require(sizeB == sizeA) { System.out.printf(notSameSizeMessage, sizeA, sizeB) }
435-
return Pair(sizeA, sizeB)
436-
}
437-
438-
/**
439-
* Creates the [Comparator] which is used to filter a list by multiple criteria
440-
* Can be thought of as a chain resembling something like
441-
* val comparator = compareBy(LaundryItem::speaker).thenBy { it.title }.thenByDescending { it.length }.thenByDescending { it.series }.thenBy { it.language }
442-
* which will then be fed into list.sortedWith(comparator), except the calls to thenBy() and thenByDescending() will also be passed [KProperty1]s
443-
* @param firstSelector used to start the chain of comparators with ascending or descending order;
444-
* should be the first of the list of conditions to be sorted by. The iteration through the sort criteria
445-
* will continue with the sort criteria after [firstSelector]
446-
* Would make explicitly private but Kotlin throws an error
447-
448-
* */
449-
@PublishedApi
450-
internal inline fun <reified T> PRIVATEgetComparator(
451-
ascending: List<Boolean>,
452-
firstSelector: KProperty1<T, Comparable<Any>?>,
453-
sortCriteria: List<String>,
454-
size: Int
455-
): Comparator<T> {
456-
var compareBy =
457-
if (ascending[0]) compareBy(firstSelector) else compareByDescending(firstSelector)
458-
for (index in 1 until size) {
459-
// unoptimized:
460-
// val isAscending = ascending[index]
461-
// val propertyToSortBy = getPropertyToSortBy<T>(sortCriteria[index])
462-
// compareBy = if (isAscending) compareBy.thenBy(propertyToSortBy) else compareBy.thenByDescending(propertyToSortBy)
463-
// optimized:
464-
compareBy =
465-
if (ascending[index]) compareBy.thenBy(PRIVATEgetPropertyToSortBy(sortCriteria[index])) else compareBy.thenByDescending(
466-
PRIVATEgetPropertyToSortBy(sortCriteria[index])
467-
)
468-
469-
}
470-
return compareBy
471-
}
472-
473-
/**
474-
* Would make explicitly private but doing so would violate Kotlin access restrictions
475-
* */
476-
@JvmName("comparatorWithExplicitKPropertylist")
477-
@PublishedApi
478-
internal fun <T> PRIVATEgetComparator(
479-
ascending: List<Boolean>,
480-
firstSelector: KProperty1<T, Comparable<Any>?>,
481-
sortCriteria: List<KProperty1<T, Comparable<Any>?>>,
482-
size: Int
483-
): Comparator<T> {
484-
var compareBy =
485-
if (ascending[0]) compareBy(firstSelector) else compareByDescending(firstSelector)
486-
for (index in 1 until size) {
487-
compareBy =
488-
if (ascending[index]) compareBy.thenBy(sortCriteria[index]) else compareBy.thenByDescending(
489-
sortCriteria[index]
490-
)
491-
492-
}
493-
return compareBy
494-
}
495-
496-
/**
497-
* Would make explicitly private but doing so would violate Kotlin access restrictions
498-
* @return null if no parameter was found
499-
* */
500-
@PublishedApi
501-
internal inline fun <reified T> PRIVATEgetPropertyToSortBy(
502-
sortCriterion: String
503-
): KProperty1<T, Comparable<Any>?> =
504-
(T::class as KClass<*>).memberProperties.find { it.name == sortCriterion } as KProperty1<T, Comparable<Any>?>?
505-
?: throw IllegalArgumentException("Parameter \"$sortCriterion\" not found")
506-
507-
/**
508-
* Returns a list containing the results of applying the given [transform] function
509-
* to each element in the original collection.
510-
* */
511-
inline fun <T, R> Iterable<T>.toListBy(transform: (T) -> R): MutableList<R> {
512-
val mutableList: MutableList<R> = mutableListOf()
513-
forEach { mutableList.add(transform(it)) }
514-
return mutableList
515-
}
516-
517-
/**
518-
* @param nullable to distinguish between nullable and not
519-
* */
520-
inline fun <T, R> Iterable<T?>.toListBy(nullable: Boolean, transform: (T) -> R): MutableList<R> {
521-
val mutableList: MutableList<R> = mutableListOf()
522-
forEach { it?.let { it1 -> mutableList.add(transform(it1)) } }
523-
return mutableList
524-
}
525-
526372
/**
527373
* Mutates the reciever list to exactly match [other]. Does not take into account whether contents are identical but have moved,
528374
* nor whether a region of the lists are matching, but one is missing the contents of another, and just overrides all of the rest
@@ -1283,6 +1129,6 @@ println("workingList2=$workingList2")*/
12831129

12841130
@JvmStatic
12851131
fun main(args: Array<String>) {
1286-
println("KotlinFunctionLibrary v4.0.0")
1132+
println("KotlinFunctionLibrary v4.1.0")
12871133
}
12881134
}

0 commit comments

Comments
 (0)