@@ -16,6 +16,7 @@ import kotlin.reflect.KProperty1
1616import kotlin.reflect.full.memberProperties
1717import kotlin.reflect.full.primaryConstructor
1818import 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