net.corda.client.fxutils / AggregatedList

AggregatedList

class AggregatedList<A, E : Any, K : Any> : TransformationList<A, E>

Given an ObservableList<E> and a grouping key K, AggregatedList groups the elements by the key into a fresh ObservableList<E> for each group and exposes the groups as an observable list of As by calling assemble on each.

Changes done to elements of the input list are reflected in the observable list of the respective group, whereas additions/removals of elements in the underlying list are reflected in the exposed ObservableList<A> by adding/deleting aggregations as expected.

The ordering of the exposed list is based on the hashCode of keys. The ordering of the groups themselves is based on the hashCode of elements.

Warning: If there are two elements E in the source list that have the same hashCode then it is not deterministic which one will be removed if one is removed from the source list

Example: val statesGroupedByCurrency = AggregatedList(states, { state -> state.currency }) { currency, group -> object { val currency = currency val states = group } }

The above creates an observable list of (currency, statesOfCurrency) pairs.

Note that update events to the source list are discarded, assuming the key of elements does not change. TODO Should we handle this case? It requires additional bookkeeping of sourceIndex->(aggregationIndex, groupIndex)



Parameters

list - The underlying list.

toKey - Function to extract the key from an element.

assemble - Function to assemble the aggregation into the exposed A.


Constructors

<init> AggregatedList(list: ObservableList<out E>, toKey: (E) -> K, assemble: (K, ObservableList<E>) -> A)

Given an ObservableList<E> and a grouping key K, AggregatedList groups the elements by the key into a fresh ObservableList<E> for each group and exposes the groups as an observable list of As by calling assemble on each.

Properties

assemble val assemble: (K, ObservableList<E>) -> A
size val size: Int
toKey val toKey: (E) -> K

Functions

get fun get(index: Int): A?
getSourceIndex fun getSourceIndex(index: Int): Int

We cannot implement this as aggregations are one to many

sourceChanged fun sourceChanged(c: Change<out E>): Unit

Extension Functions

associateBy fun <K, A, B> ObservableList<out A>.associateBy(toKey: (A) -> K, assemble: (K, A) -> B): ObservableMap<K, B>

data class Person(val height: Long) val people: ObservableList = (..) val nameToHeight: ObservableMap<String, Long> = people.associateBy(Person::name) { name, person -> person.height }

fun <K, A> ObservableList<out A>.associateBy(toKey: (A) -> K): ObservableMap<K, A>

val people: ObservableList = (..) val nameToPerson: ObservableMap<String, Person> = people.associateBy(Person::name)

associateByAggregation fun <K : Any, A : Any, B> ObservableList<out A>.associateByAggregation(toKey: (A) -> K, assemble: (K, A) -> B): ObservableMap<K, ObservableList<B>>

val people: ObservableList = (..) val heightToNames: ObservableMap<Long, ObservableList> = people.associateByAggregation(Person::height) { name, person -> person.name }

fun <K : Any, A : Any> ObservableList<out A>.associateByAggregation(toKey: (A) -> K): ObservableMap<K, ObservableList<A>>

val people: ObservableList = (..) val heightToPeople: ObservableMap<Long, ObservableList> = people.associateByAggregation(Person::height)

filter fun <A> ObservableList<out A>.filter(predicate: ObservableValue<(A) -> Boolean>): ObservableList<A>

enum class FilterCriterion { HEIGHT, NAME } val filterCriterion: ObservableValue = (..) val people: ObservableList = (..) fun filterFunction(filterCriterion: FilterCriterion): (Person) -> Boolean { .. }

filterNotNull fun <A> ObservableList<out A?>.filterNotNull(): ObservableList<A>

data class Dog(val owner: Person?) val dogs: ObservableList = (..) val owners: ObservableList = dogs.map(Dog::owner).filterNotNull()

first fun <A> ObservableList<A>.first(): ObservableValue<A?>
foldObservable fun <A, B> ObservableList<out A>.foldObservable(initial: B, folderFunction: (B, A) -> B): ObservableValue<B>

val people: ObservableList = (..) val concatenatedNames = people.foldObservable("", { names, person -> names + person.name }) val concatenatedNames2 = people.map(Person::name).fold("", String::plus)

getValueAt fun <A> ObservableList<A>.getValueAt(index: Int): ObservableValue<A?>
indexOfOrThrow fun <T> List<T>.indexOfOrThrow(item: T): Int

Returns the index of the given item or throws IllegalArgumentException if not found.

last fun <A> ObservableList<A>.last(): ObservableValue<A?>
leftOuterJoin fun <A : Any, B : Any, C, K : Any> ObservableList<A>.leftOuterJoin(rightTable: ObservableList<B>, leftToJoinKey: (A) -> K, rightToJoinKey: (B) -> K, assemble: (A, ObservableList<B>) -> C): ObservableList<C>

data class Person(val name: String, val managerName: String) val people: ObservableList = (..) val managerEmployeeMapping: ObservableList<Pair<Person, ObservableList>> = people.leftOuterJoin(people, Person::name, Person::managerName) { manager, employees -> Pair(manager, employees) }

fun <A : Any, B : Any, K : Any> ObservableList<A>.leftOuterJoin(rightTable: ObservableList<B>, leftToJoinKey: (A) -> K, rightToJoinKey: (B) -> K): ObservableMap<K, <ERROR CLASS><ObservableList<A>, ObservableList<B>>>

data class Person(name: String, favouriteSpecies: Species) data class Animal(name: String, species: Species) val people: ObservableList = (..) val animals: ObservableList = (..) val peopleToFavouriteAnimals: ObservableMap<Species, Pair<ObservableList, ObservableList>> = people.leftOuterJoin(animals, Person::favouriteSpecies, Animal::species)

map fun <A, B> ObservableList<out A>.map(cached: Boolean = true, function: (A) -> B): ObservableList<B>

val dogs: ObservableList = (..) val dogOwners: ObservableList = dogs.map { it.owner }

noneOrSingle fun <T> Iterable<T>.noneOrSingle(predicate: (T) -> Boolean): T?

Returns the single element matching the given predicate, or null if element was not found, or throws if more than one element was found.

fun <T> Iterable<T>.noneOrSingle(): T?

Returns single element, or null if element was not found, or throws if more than one element was found.