Merge "Add useful utils to CollectionUtils"
This commit is contained in:
commit
55de7e4c84
2 changed files with 148 additions and 0 deletions
|
|
@ -18,12 +18,15 @@ package com.android.net.module.util;
|
|||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
|
|
@ -291,4 +294,100 @@ public final class CollectionUtils {
|
|||
@NonNull final Predicate<? super T> condition) {
|
||||
return -1 != indexOf(haystack, condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard map function, but returns a new modifiable ArrayList
|
||||
*
|
||||
* This returns a new list that contains, for each element of the source collection, its
|
||||
* image through the passed transform.
|
||||
* Elements in the source can be null if the transform accepts null inputs.
|
||||
* Elements in the output can be null if the transform ever returns null.
|
||||
* This function never returns null. If the source collection is empty, it returns the
|
||||
* empty list.
|
||||
* Contract : this method calls the transform function exactly once for each element in the
|
||||
* list, in iteration order.
|
||||
*
|
||||
* @param source the source collection
|
||||
* @param transform the function to transform the elements
|
||||
* @param <T> type of source elements
|
||||
* @param <R> type of destination elements
|
||||
* @return an unmodifiable list of transformed elements
|
||||
*/
|
||||
@NonNull
|
||||
public static <T, R> ArrayList<R> map(@NonNull final Collection<T> source,
|
||||
@NonNull final Function<? super T, ? extends R> transform) {
|
||||
final ArrayList<R> dest = new ArrayList<>(source.size());
|
||||
for (final T e : source) {
|
||||
dest.add(transform.apply(e));
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard zip function, but returns a new modifiable ArrayList
|
||||
*
|
||||
* This returns a list of pairs containing, at each position, a pair of the element from the
|
||||
* first list at that index and the element from the second list at that index.
|
||||
* Both lists must be the same size. They may contain null.
|
||||
*
|
||||
* The easiest way to visualize what's happening is to think of two lists being laid out next
|
||||
* to each other and stitched together with a zipper.
|
||||
*
|
||||
* Contract : this method will read each element of each list exactly once, in some unspecified
|
||||
* order. If it throws, it will not read any element.
|
||||
*
|
||||
* @param first the first list of elements
|
||||
* @param second the second list of elements
|
||||
* @param <T> the type of first elements
|
||||
* @param <R> the type of second elements
|
||||
* @return the zipped list
|
||||
*/
|
||||
@NonNull
|
||||
public static <T, R> ArrayList<Pair<T, R>> zip(@NonNull final List<T> first,
|
||||
@NonNull final List<R> second) {
|
||||
final int size = first.size();
|
||||
if (size != second.size()) {
|
||||
throw new IllegalArgumentException("zip : collections must be the same size");
|
||||
}
|
||||
final ArrayList<Pair<T, R>> dest = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
dest.add(new Pair<>(first.get(i), second.get(i)));
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new ArrayMap that associates each key with the value at the same index.
|
||||
*
|
||||
* Both lists must be the same size.
|
||||
* Both keys and values may contain null.
|
||||
* Keys may not contain the same value twice.
|
||||
*
|
||||
* Contract : this method will read each element of each list exactly once, but does not
|
||||
* specify the order, except if it throws in which case the number of reads is undefined.
|
||||
*
|
||||
* @param keys The list of keys
|
||||
* @param values The list of values
|
||||
* @param <T> The type of keys
|
||||
* @param <R> The type of values
|
||||
* @return The associated map
|
||||
*/
|
||||
@NonNull
|
||||
public static <T, R> ArrayMap<T, R> assoc(
|
||||
@NonNull final List<T> keys, @NonNull final List<R> values) {
|
||||
final int size = keys.size();
|
||||
if (size != values.size()) {
|
||||
throw new IllegalArgumentException("assoc : collections must be the same size");
|
||||
}
|
||||
final ArrayMap<T, R> dest = new ArrayMap<>(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
final T key = keys.get(i);
|
||||
if (dest.containsKey(key)) {
|
||||
throw new IllegalArgumentException(
|
||||
"assoc : keys may not contain the same value twice");
|
||||
}
|
||||
dest.put(key, values.get(i));
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.android.testutils.assertThrows
|
|||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertSame
|
||||
|
|
@ -133,4 +134,52 @@ class CollectionUtilsTest {
|
|||
assertSame(CollectionUtils.findLast(listMulti) { it == "E" }, listMulti[7])
|
||||
assertNull(CollectionUtils.findLast(listMulti) { it == "F" })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMap() {
|
||||
val listAE = listOf("A", "B", "C", "D", "E", null)
|
||||
assertEquals(listAE.map { "-$it-" }, CollectionUtils.map(listAE) { "-$it-" })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testZip() {
|
||||
val listAE = listOf("A", "B", "C", "D", "E")
|
||||
val list15 = listOf(1, 2, 3, 4, 5)
|
||||
// Normal #zip returns kotlin.Pair, not android.util.Pair
|
||||
assertEquals(list15.zip(listAE).map { android.util.Pair(it.first, it.second) },
|
||||
CollectionUtils.zip(list15, listAE))
|
||||
val listNull = listOf("A", null, "B", "C", "D")
|
||||
assertEquals(list15.zip(listNull).map { android.util.Pair(it.first, it.second) },
|
||||
CollectionUtils.zip(list15, listNull))
|
||||
assertEquals(emptyList<android.util.Pair<Int, Int>>(),
|
||||
CollectionUtils.zip(emptyList<Int>(), emptyList<Int>()))
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
// Different size
|
||||
CollectionUtils.zip(listOf(1, 2), list15)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAssoc() {
|
||||
val listADA = listOf("A", "B", "C", "D", "A")
|
||||
val list15 = listOf(1, 2, 3, 4, 5)
|
||||
assertEquals(list15.zip(listADA).toMap(), CollectionUtils.assoc(list15, listADA))
|
||||
|
||||
// Null key is fine
|
||||
val assoc = CollectionUtils.assoc(listOf(1, 2, null), listOf("A", "B", "C"))
|
||||
assertEquals("C", assoc[null])
|
||||
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
// Same key multiple times
|
||||
CollectionUtils.assoc(listOf("A", "B", "A"), listOf(1, 2, 3))
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
// Same key multiple times, but it's null
|
||||
CollectionUtils.assoc(listOf(null, "B", null), listOf(1, 2, 3))
|
||||
}
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
// Different size
|
||||
CollectionUtils.assoc(listOf(1, 2), list15)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue