@@ -217,6 +217,56 @@ provide let mapi = (fn, list) => {
217217 iter(fn, list, 0)
218218}
219219
220+ /**
221+ * Produces a new list initialized with the results of a mapper function
222+ * called on each element of the input list.
223+ * The mapper function can return `None` to exclude the element from the new list.
224+ *
225+ * @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new list
226+ * @param list: The list to iterate
227+ * @returns The new list with filtered mapped values
228+ *
229+ * @example List.filterMap(x => if (x % 2 == 0) Some(toString(x)) else None, [1, 2, 3, 4]) == ["2", "4"]
230+ *
231+ * @since v0.7.0
232+ */
233+ provide let rec filterMap = (fn, list) => {
234+ match (list) {
235+ [] => [],
236+ [first, ...rest] => match (fn(first)) {
237+ Some(v) => [v, ...filterMap(fn, rest)],
238+ None => filterMap(fn, rest),
239+ },
240+ }
241+ }
242+
243+ /**
244+ * Produces a new list initialized with the results of a mapper function
245+ * called on each element of the input list and its index.
246+ * The mapper function can return `None` to exclude the element from the new list.
247+ *
248+ * @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new list
249+ * @param list: The list to iterate
250+ * @returns The new list with filtered mapped values
251+ *
252+ * @example List.filterMapi((x, i) => if (x % 2 == 0) Some(toString(x)) else None, [1, 2, 3, 4]) == ["2", "4"]
253+ * @example List.filterMapi((x, i) => if (i == 0) Some(toString(x)) else None, [1, 2, 3, 4]) == ["1"]
254+ *
255+ * @since v0.7.0
256+ */
257+ provide let filterMapi = (fn, list) => {
258+ let rec iter = (fn, list, index) => {
259+ match (list) {
260+ [] => [],
261+ [first, ...rest] => match (fn(first, index)) {
262+ Some(v) => [v, ...iter(fn, rest, index + 1)],
263+ None => iter(fn, rest, index + 1),
264+ },
265+ }
266+ }
267+ iter(fn, list, 0)
268+ }
269+
220270/**
221271 * Produces a new list by calling a function on each element
222272 * of the input list. Each iteration produces an intermediate
@@ -242,7 +292,7 @@ provide let rec flatMap = (fn, list) => {
242292 *
243293 * @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
244294 * @param list: The list to check
245- * @returns `true` if all elements satify the condition or `false` otherwise
295+ * @returns `true` if all elements satisfy the condition or `false` otherwise
246296 *
247297 * @since v0.1.0
248298 */
@@ -260,7 +310,7 @@ provide let rec every = (fn, list) => {
260310 *
261311 * @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
262312 * @param list: The list to iterate
263- * @returns `true` if one or more elements satify the condition or `false` otherwise
313+ * @returns `true` if one or more elements satisfy the condition or `false` otherwise
264314 *
265315 * @since v0.1.0
266316 */
@@ -769,7 +819,7 @@ provide let rec takeWhile = (fn, list) => {
769819}
770820
771821/**
772- * Finds the first element in a list that satifies the given condition.
822+ * Finds the first element in a list that satisfies the given condition.
773823 *
774824 * @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
775825 * @param list: The list to search
@@ -787,7 +837,7 @@ provide let rec find = (fn, list) => {
787837}
788838
789839/**
790- * Finds the first index in a list where the element satifies the given condition.
840+ * Finds the first index in a list where the element satisfies the given condition.
791841 *
792842 * @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
793843 * @param list: The list to search
@@ -808,6 +858,31 @@ provide let findIndex = (fn, list) => {
808858 findItemIndex(list, 0)
809859}
810860
861+ /**
862+ * Finds the first element in a list that satisfies the given condition and
863+ * returns the result of applying a mapper function to it.
864+ *
865+ * @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
866+ * @param list: The list to search
867+ * @returns `Some(mapped)` containing the first value found with the given mapping or `None` otherwise
868+ *
869+ * @example
870+ * let jsonObject = [(1, 'a'), (2, 'b'), (1, 'c')]
871+ * let getItem = (key, obj) => List.findMap(((k, v)) => if (k == key) Some(v) else None, obj)
872+ * assert getItem(1, jsonObject) == Some('a')
873+ *
874+ * @since v0.7.0
875+ */
876+ provide let rec findMap = (fn, list) => {
877+ match (list) {
878+ [] => None,
879+ [first, ...rest] => match (fn(first)) {
880+ None => findMap(fn, rest),
881+ Some(v) => Some(v),
882+ },
883+ }
884+ }
885+
811886/**
812887 * Combines two lists into a Cartesian product of tuples containing
813888 * all ordered pairs `(a, b)`.
0 commit comments