Skip to content

Commit

Permalink
MultiSet consistent methods, Array setAll, MutableCollection popRandom (
Browse files Browse the repository at this point in the history
  • Loading branch information
lbressler13 authored Mar 30, 2023
1 parent f50a48c commit 741dac1
Show file tree
Hide file tree
Showing 57 changed files with 2,280 additions and 315 deletions.
1 change: 0 additions & 1 deletion .github/workflows/basic_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ on:
push:
branches-ignore:
- "main"
pull_request:

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion kotlin-utils/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

group = "xyz.lbres"
version = "0.4.0"
version = "1.0.0"

repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.array.ext

/**
* Assign all elements to have a given value
*
* @param value [T]: value to assign
*/
fun <T> Array<T>.setAllValues(value: T) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.booleanarray.ext

/**
* Assign all elements to have a given value
*
* @param value [Boolean]: value to assign
*/
fun BooleanArray.setAllValues(value: Boolean) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.bytearray.ext

/**
* Assign all elements to have a given value
*
* @param value [Byte]: value to assign
*/
fun ByteArray.setAllValues(value: Byte) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.chararray.ext

/**
* Assign all elements to have a given value
*
* @param value [Char]: value to assign
*/
fun CharArray.setAllValues(value: Char) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

package xyz.lbres.kotlinutils.classes.labelled

import xyz.lbres.kotlinutils.general.labelled.Labelled

/**
* Code for the Labelled class has been moved to the general/labelled package.
* This file exists only to avoid breaking existing functionality that uses the class at this path.
*/

typealias Labelled<T> = Labelled<T>
private const val packageName = "xyz.lbres.kotlinutils.general.labelled"

@Deprecated("Class moved to package $packageName.", ReplaceWith("$packageName.Labelled", "$packageName.Labelled"), DeprecationLevel.WARNING)
data class Labelled<T>(val value: T, val label: String)
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,27 @@ package xyz.lbres.kotlinutils.classes.multiset
* This file exists only to avoid breaking existing functionality that uses the class at this path.
*/

typealias MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.MultiSet<E>
typealias MutableMultiSet<E> = xyz.lbres.kotlinutils.set.multiset.MutableMultiSet<E>
fun <E> multiSetOf(vararg elements: E): xyz.lbres.kotlinutils.set.multiset.MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.multiSetOf(*elements)
fun <E> mutableMultiSetOf(vararg elements: E): xyz.lbres.kotlinutils.set.multiset.MutableMultiSet<E> = xyz.lbres.kotlinutils.set.multiset.mutableMultiSetOf(*elements)
fun <E> emptyMultiSet(): xyz.lbres.kotlinutils.set.multiset.MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.emptyMultiSet()
fun <E> MultiSet(size: Int, init: (Int) -> E): xyz.lbres.kotlinutils.set.multiset.MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.MultiSet(size, init)
fun <E> MutableMultiSet(size: Int, init: (Int) -> E): xyz.lbres.kotlinutils.set.multiset.MutableMultiSet<E> = xyz.lbres.kotlinutils.set.multiset.MutableMultiSet(size, init)
private const val packageName = "xyz.lbres.kotlinutils.set.multiset"
private const val functionMessage = "Function moved to package $packageName."
private const val interfaceMessage = "Interface moved to package $packageName."

@Deprecated(interfaceMessage, ReplaceWith("$packageName.MultiSet", "$packageName.MultiSet"), DeprecationLevel.WARNING)
interface MultiSet<E> : xyz.lbres.kotlinutils.set.multiset.MultiSet<E>

@Deprecated(interfaceMessage, ReplaceWith("$packageName.MutableMultiSet", "$packageName.MutableMultiSet"), DeprecationLevel.WARNING)
interface MutableMultiSet<E> : xyz.lbres.kotlinutils.set.multiset.MutableMultiSet<E>

@Deprecated(functionMessage, ReplaceWith("$packageName.multiSetOf(elements)", "$packageName.multiSetOf"), DeprecationLevel.WARNING)
fun <E> multiSetOf(vararg elements: E): MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.multiSetOf(*elements) as MultiSet

@Deprecated(functionMessage, ReplaceWith("$packageName.mutableMultiSetOf(elements)", "$packageName.mutableMultiSetOf"), DeprecationLevel.WARNING)
fun <E> mutableMultiSetOf(vararg elements: E): MutableMultiSet<E> = xyz.lbres.kotlinutils.set.multiset.mutableMultiSetOf(*elements) as MutableMultiSet

@Deprecated(functionMessage, ReplaceWith("$packageName.emptyMultiSet()", "$packageName.emptyMultiSet"), DeprecationLevel.WARNING)
fun <E> emptyMultiSet(): MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.emptyMultiSet<E>() as MultiSet

@Deprecated(functionMessage, ReplaceWith("$packageName.MultiSet(size, init)", "$packageName.MultiSet"), DeprecationLevel.WARNING)
fun <E> MultiSet(size: Int, init: (Int) -> E): MultiSet<E> = xyz.lbres.kotlinutils.set.multiset.MultiSet(size, init) as MultiSet

@Deprecated(functionMessage, ReplaceWith("$packageName.MutableMultiSet(size, init)", "$packageName.MutableMultiSet"), DeprecationLevel.WARNING)
fun <E> MutableMultiSet(size: Int, init: (Int) -> E): MutableMultiSet<E> = xyz.lbres.kotlinutils.set.multiset.MutableMultiSet(size, init) as MutableMultiSet
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package xyz.lbres.kotlinutils.collection.mutable.ext

/**
* Remove a random element from the collection and return it
*
* @return [T]?: an element from the collection, or `null` if the collection is empty
*/
fun <T> MutableCollection<T>.popRandom(): T? {
if (isEmpty()) {
return null
}

val element = random()
remove(element)
return element
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.doublearray.ext

/**
* Assign all elements to have a given value
*
* @param value [Double]: value to assign
*/
fun DoubleArray.setAllValues(value: Double) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.floatarray.ext

/**
* Assign all elements to have a given value
*
* @param value [Float]: value to assign
*/
fun FloatArray.setAllValues(value: Float) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.intarray.ext

/**
* Assign all elements to have a given value
*
* @param value [Int]: value to assign
*/
fun IntArray.setAllValues(value: Int) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
package xyz.lbres.kotlinutils.list.mutablelist.ext

import xyz.lbres.kotlinutils.collection.mutable.ext.popRandom

/**
* Remove a random element from list and return it
* Remove a random element from list and return it.
*
* @return [T]: an element from the list, or null if the list is empty
* @return [T]?: an element from the list, or `null` if the list is empty
*/
fun <T> MutableList<T>.popRandom(): T? {
if (isEmpty()) {
return null
}

val index = indices.random()
val element = get(index)
removeAt(index)
return element
}
fun <T> MutableList<T>.popRandom(): T? = popRandom()
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.lbres.kotlinutils.longarray.ext

/**
* Assign all elements to have a given value
*
* @param value [Long]: value to assign
*/
fun LongArray.setAllValues(value: Long) {
indices.forEach { set(it, value) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package xyz.lbres.kotlinutils.set.multiset
* The interface supports only read access to the values.
* Read/write access is available through the [MutableMultiSet] interface.
*/
interface MultiSet<E> : Set<E> {
interface MultiSet<E> : Collection<E> {
/**
* All distinct values contained in the MultiSet
*/
Expand All @@ -23,26 +23,58 @@ interface MultiSet<E> : Set<E> {
* Create a new MultiSet with values that are in this set but not the other set.
* If there are multiple occurrences of a value, the number of occurrences in the other set will be subtracted from the number in this MultiSet.
*
* @param other [MultiSet]<[E]>: values to subtract from this MultiSet
* @return [MultiSet]<[E]>: MultiSet containing the items in this MultiSet but not the other
* @param other [MultiSet]<E>: values to subtract from this MultiSet
* @return [MultiSet]<E>: MultiSet containing the items in this MultiSet but not the other
*/
operator fun minus(other: MultiSet<E>): MultiSet<E>

/**
* Create a new MultiSet with all values from both sets.
* If there are multiple occurrences of a value, the number of occurrences in the other set will be added to the number in this MultiSet.
*
* @param other [MultiSet]<[E]>: values to add to this MultiSet
* @return [MultiSet]<[E]>: MultiSet containing all values from both MultiSets
* @param other [MultiSet]<E>: values to add to this MultiSet
* @return [MultiSet]<E>: MultiSet containing all values from both MultiSets
*/
operator fun plus(other: MultiSet<E>): MultiSet<E>

/**
* Create a new MultiSet with values that are shared between the sets.
* If there are multiple occurrences of a value, the smaller number of occurrences will be used.
*
* @param other [MultiSet]<[E]>: values to intersect with this MultiSet
* @return [MultiSet]<[E]>: MultiSet containing only values that are in both MultiSets
* @param other [MultiSet]<E>: values to intersect with this MultiSet
* @return [MultiSet]<E>: MultiSet containing only values that are in both MultiSets
*/
fun intersect(other: MultiSet<E>): MultiSet<E>
infix fun intersect(other: MultiSet<E>): MultiSet<E>

companion object {
/**
* [plus] implementation that can be used with any [MultiSet] implementations.
* May be less efficient than class-specific implementations.
*
* @param multiSet1 [MultiSet]<E>: first MultiSet in addition
* @param multiSet2 [MultiSet]<E>: second MultiSet in addition
* @return [MultiSet]<E>: MultiSet containing all values from both sets
*/
fun <E> genericPlus(multiSet1: MultiSet<E>, multiSet2: MultiSet<E>): MultiSet<E> = genericMultiSetPlus(multiSet1, multiSet2)

/**
* [minus] implementation that can be used with any [MultiSet] implementations.
* May be less efficient than class-specific implementations.
*
* @param multiSet1 [MultiSet]<E>: first MultiSet in subtraction
* @param multiSet2 [MultiSet]<E>: second MultiSet in subtraction
* @return [MultiSet]<E>: MultiSet containing the items in the first MultiSet but not the second
*/
fun <E> genericMinus(multiSet1: MultiSet<E>, multiSet2: MultiSet<E>): MultiSet<E> = genericMultiSetMinus(multiSet1, multiSet2)

/**
* [minus] implementation that can be used with any [MultiSet] implementations.
* May be less efficient than class-specific implementations.
*
* @param multiSet1 [MultiSet]<E>: first MultiSet in intersect
* @param multiSet2 [MultiSet]<E>: second MultiSet in intersect
* @return [MultiSet]<E>: MultiSet containing only values that are in both sets
*/
fun <E> genericIntersect(multiSet1: MultiSet<E>, multiSet2: MultiSet<E>): MultiSet<E> = genericMultiSetIntersect(multiSet1, multiSet2)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package xyz.lbres.kotlinutils.set.multiset

import kotlin.math.max
import kotlin.math.min

/**
* Generic [MultiSet.plus] implementation that can be applied to any two MultiSets.
*
* @param multiSet1 [MultiSet]<E>: first MultiSet in addition
* @param multiSet2 [MultiSet]<E>: second MultiSet in addition
* @return [MultiSet]<E>: MultiSet containing all values from both MultiSets
*/
internal fun <E> genericMultiSetPlus(multiSet1: MultiSet<E>, multiSet2: MultiSet<E>): MultiSet<E> {
val newSet = mutableMultiSetOf<E>()
val distinctValues = multiSet1.distinctValues + multiSet2.distinctValues

distinctValues.forEach { element ->
val totalCount = multiSet1.getCountOf(element) + multiSet2.getCountOf(element)
repeat(totalCount) { newSet.add(element) }
}

return newSet
}

/**
* Generic [MultiSet.minus] implementation that can be applied to any two MultiSets.
*
* @param multiSet1 [MultiSet]<E>: first MultiSet in subtraction
* @param multiSet2 [MultiSet]<E>: second MultiSet in subtraction
* @return [MultiSet]<E>: MultiSet containing the items in the first MultiSet but not the second
*/
internal fun <E> genericMultiSetMinus(multiSet1: MultiSet<E>, multiSet2: MultiSet<E>): MultiSet<E> {
val newSet = mutableMultiSetOf<E>()
val distinctValues = multiSet1.distinctValues + multiSet2.distinctValues

distinctValues.forEach { element ->
val totalCount = max(0, multiSet1.getCountOf(element) - multiSet2.getCountOf(element))
repeat(totalCount) { newSet.add(element) }
}

return newSet
}

/**
* Generic [MultiSet.intersect] implementation that can be applied to any two MultiSets.
*
* @param multiSet1 [MultiSet]<E>: first MultiSet in intersection
* @param multiSet2 [MultiSet]<E>: second MultiSet in intersection
* @return [MultiSet]<E>: MultiSet containing only values that are in both MultiSets
*/
internal fun <E> genericMultiSetIntersect(multiSet1: MultiSet<E>, multiSet2: MultiSet<E>): MultiSet<E> {
val newSet = mutableMultiSetOf<E>()
val distinctValues = multiSet1.distinctValues intersect multiSet2.distinctValues

distinctValues.forEach { element ->
val totalCount = min(multiSet1.getCountOf(element), multiSet2.getCountOf(element))
repeat(totalCount) { newSet.add(element) }
}

return newSet
}
Loading

0 comments on commit 741dac1

Please sign in to comment.