Filter items from a list

Remove specific items from lists using fold in Clarity


(define-read-only (filter-item (l (list 100 uint)) (remove uint))
(get newList (fold remove-value l { compareTo: remove, newList: (list) }))
)
(define-private (remove-value (listValue uint) (trackerTuple { compareTo: uint, newList: (list 100 uint) }))
(merge trackerTuple {newList:
(if (is-eq listValue (get compareTo trackerTuple))
(get newList trackerTuple)
(unwrap-panic (as-max-len? (append (get newList trackerTuple) listValue) u100))
)
})
)
;; Example usage
(filter-item (list u1 u2 u3 u2 u4) u2) ;; Returns (u1 u3 u4)

Use cases

  • Removing blacklisted addresses from access lists
  • Filtering out completed tasks from todo lists
  • Excluding specific tokens from portfolios
  • Data cleanup in smart contracts

Key concepts

This pattern uses fold to iterate through a list and build a new list:

  • Accumulator: Tracks the value to remove and builds the new list
  • Conditional append: Only adds items that don't match the filter
  • Type safety: Maintains list type and maximum length

Filter multiple values

(define-read-only (filter-multiple (l (list 100 uint)) (removeList (list 10 uint)))
(fold filter-item removeList l)
)
;; Example: Remove multiple values
(filter-multiple (list u1 u2 u3 u4 u5) (list u2 u4))
;; Returns (u1 u3 u5)

Filter with predicate function

(define-read-only (filter-greater-than (l (list 100 uint)) (threshold uint))
(get newList
(fold filter-by-threshold l { threshold: threshold, newList: (list) })
)
)
(define-private (filter-by-threshold (value uint) (tracker { threshold: uint, newList: (list 100 uint) }))
(merge tracker {
newList: (if (> value (get threshold tracker))
(unwrap-panic (as-max-len? (append (get newList tracker) value) u100))
(get newList tracker)
)
})
)
;; Keep only values greater than 10
(filter-greater-than (list u5 u15 u8 u20 u3) u10)
;; Returns (u15 u20)

Advanced filtering patterns

;; Filter principals from a list
(define-read-only (filter-principal
(principals (list 100 principal))
(remove principal))
(get newList
(fold remove-principal principals {
compareTo: remove,
newList: (list as principal)
})
)
)
;; Filter with custom comparison
(define-read-only (filter-custom
(items (list 100 { id: uint, active: bool })) )
(get newList
(fold filter-inactive items { newList: (list) })
)
)
(define-private (filter-inactive
(item { id: uint, active: bool })
(tracker { newList: (list 100 { id: uint, active: bool }) }))
(merge tracker {
newList: (if (get active item)
(unwrap-panic (as-max-len? (append (get newList tracker) item) u100))
(get newList tracker)
)
})
)
Performance note

Filtering creates a new list, so be mindful of gas costs with large lists. Consider storing data in maps if you need frequent filtering operations.