Ionut Bilica
Ionut Bilica

Reputation: 434

Replicate Java peek stream method in Clojure

In Java I can do this

list.stream().peek(System.out::println).filter(i -> i >= 0).findFirst();

This will find the first positive number in a list, printing all numbers since the begining until the first positive number.

I need something similar in Clojure, but I can't find a equivalent for peek. peek does something different in Clojure. I need to create a side effect without consuming the sequence, intermediary. Just as elements pass through, they should be passed to a function. I could implement it myself, but I don't want to reinvent something existing. Seems like basic functionality, I was unable to find the right function to call).

Upvotes: 1

Views: 177

Answers (2)

Didier A.
Didier A.

Reputation: 4816

Just use map in combination with doto and transducers to have it do a side effect and otherwise be a passthrough:

(into []
 (comp
  (map #(doto % println))
  (filter pos?)
  (take 1))
 [-1 -2 -3 4 5])

Or for what you said in your comment you can use do for example:

(->>
 (repeatedly #(rand-nth [1 nil nil]))
 (into []
  (comp
   (map #(do (when (nil? %) (Thread/sleep 1000)) %))
   (remove nil?)
   (take 1)))
 first)

I'm using transducers, because lazy sequences are not guaranteed to be one at a time, due to chunking, and special care is needed if you want to avoid that, so it's just much better and easier in a case where you want to mix in side-effects inside a data transformation pipeline to use transducers instead.

Upvotes: 1

Alan Thompson
Alan Thompson

Reputation: 29984

If you study the Clojure CheatSheet, you can find the function split-with which does pretty much what you want:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(dotest
  (let [[dropped kept] (split-with #(neg? %) (range -10 10))]
    (is= dropped [-10 -9 -8 -7 -6 -5 -4 -3 -2 -1])
    (is= kept [0 1 2 3 4 5 6 7 8 9])
    (is= 0 (first kept))))

If you need something in the future and can't find a built-in function that works, you can always write simple loops (or "recursion") using loop/recur.

Please also see this list of documentation.

Upvotes: 0

Related Questions