Add findFirst and findLast to CollectionsUtils
Test: new tests in this patch
Change-Id: Ie13ee7f50832ffec1febe4f4596d0b26e4c4a2f6
diff --git a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
index a16ef33..73f6cd8 100644
--- a/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/CollectionUtils.java
@@ -22,6 +22,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
@@ -219,4 +220,38 @@
return haystack.containsAll(needles);
}
+ /**
+ * Returns the first item of a collection that matches the predicate.
+ * @param haystack The collection to search.
+ * @param condition The predicate to match.
+ * @param <T> The type of element in the collection.
+ * @return The first element matching the predicate, or null if none.
+ */
+ @Nullable
+ public static <T> T findFirst(Collection<T> haystack, Predicate<? super T> condition) {
+ for (T needle : haystack) {
+ if (condition.test(needle)) return needle;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the last item of a List that matches the predicate.
+ * @param haystack The List to search.
+ * @param condition The predicate to match.
+ * @param <T> The type of element in the list.
+ * @return The last element matching the predicate, or null if none.
+ */
+ // There is no way to reverse iterate a Collection in Java (e.g. the collection may
+ // be a single-linked list), so implementing this on Collection is necessarily very
+ // wasteful (store and reverse a copy, test all elements, or recurse to the end of the
+ // list to test on the up path and possibly blow the call stack)
+ @Nullable
+ public static <T> T findLast(List<T> haystack, Predicate<? super T> condition) {
+ for (int i = haystack.size() - 1; i >= 0; --i) {
+ final T needle = haystack.get(i);
+ if (condition.test(needle)) return needle;
+ }
+ return null;
+ }
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
index 911483a..2de92f4 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/CollectionUtilsTest.kt
@@ -22,6 +22,8 @@
import org.junit.runner.RunWith
import kotlin.test.assertEquals
import kotlin.test.assertFalse
+import kotlin.test.assertNull
+import kotlin.test.assertSame
import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
@@ -86,4 +88,27 @@
assertEquals(3, CollectionUtils.total(longArrayOf(1, 1, 1)))
assertEquals(0, CollectionUtils.total(null))
}
+
+ @Test
+ fun testFindFirstFindLast() {
+ val listAE = listOf("A", "B", "C", "D", "E")
+ assertSame(CollectionUtils.findFirst(listAE) { it == "A" }, listAE[0])
+ assertSame(CollectionUtils.findFirst(listAE) { it == "B" }, listAE[1])
+ assertSame(CollectionUtils.findFirst(listAE) { it == "E" }, listAE[4])
+ assertNull(CollectionUtils.findFirst(listAE) { it == "F" })
+ assertSame(CollectionUtils.findLast(listAE) { it == "A" }, listAE[0])
+ assertSame(CollectionUtils.findLast(listAE) { it == "B" }, listAE[1])
+ assertSame(CollectionUtils.findLast(listAE) { it == "E" }, listAE[4])
+ assertNull(CollectionUtils.findLast(listAE) { it == "F" })
+
+ val listMulti = listOf("A", "B", "A", "C", "D", "E", "A", "E")
+ assertSame(CollectionUtils.findFirst(listMulti) { it == "A" }, listMulti[0])
+ assertSame(CollectionUtils.findFirst(listMulti) { it == "B" }, listMulti[1])
+ assertSame(CollectionUtils.findFirst(listMulti) { it == "E" }, listMulti[5])
+ assertNull(CollectionUtils.findFirst(listMulti) { it == "F" })
+ assertSame(CollectionUtils.findLast(listMulti) { it == "A" }, listMulti[6])
+ assertSame(CollectionUtils.findLast(listMulti) { it == "B" }, listMulti[1])
+ assertSame(CollectionUtils.findLast(listMulti) { it == "E" }, listMulti[7])
+ assertNull(CollectionUtils.findLast(listMulti) { it == "F" })
+ }
}