class AggregatedList<A, E, 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.
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)
list
- The underlying list.toKey
- Function to extract the key from an element.assemble
- Function to assemble the aggregation into the exposed A.<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. |
assemble |
val assemble: (K, ObservableList<E>) -> A |
size |
val size: Int |
toKey |
val toKey: (E) -> K |
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 |
filter |
fun <A> ObservableList<out A>.filter(predicate: ObservableValue<(A) -> Boolean>): ObservableList<out A> enum class FilterCriterion { HEIGHT, NAME } val filterCriterion: ObservableValue = (..) val people: ObservableList = (..) fun filterFunction(filterCriterion: FilterCriterion): (Person) -> Boolean { .. } |
fold |
fun <A, B> ObservableList<out A>.fold(initial: B, folderFunction: (B, A) -> B): ObservableValue<B> val people: ObservableList = (..) val concatenatedNames = people.fold("", { names, person -> names + person.name }) val concatenatedNames2 = people.map(Person::name).fold("", String::plus) |
indexOfOrThrow |
fun <T> List<T>.indexOfOrThrow(item: T): Int Returns the index of the given item or throws IllegalArgumentException if not found. |
map |
fun <A, B> ObservableList<out A>.map(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 fun <T> Iterable<T>.noneOrSingle(): T? Returns single element, or |