1

I would like to have a search and replace on the values only inside data structures:

(def str [1 2 3 
              {:a 1 
               :b 2 
               1  3}])

and

(subst  str  1  2) 

to return

[2 2 3 {:a 2, :b 2, 1 3}]

Another example:

(def str2  {[1 2 3] x, {a 1 b 2} y} )

and

(subst  str2  1  2) 

to return

{[1 2 3] x, {a 1 b 2} y}

Since the 1's are keys in a map they are not replaced

6
  • The restriction that only values and not map keys should be replaced means you'll likely be rolling your own. Commented Sep 18, 2014 at 15:09
  • In {[1 2 3] x, {a 1 b 2} y}, the both 1s are values inside keys. Are you saying that values only are naked values or naked values inside values? Commented Sep 19, 2014 at 7:23
  • Function in my answer seems to work just like you've described. I wonder if it works for you and if not, what's the problem with it? Commented Sep 23, 2014 at 16:17
  • I meant only naked value, not values in keys Commented Sep 23, 2014 at 18:19
  • @Zubair, try it for yourself, that's the way it works (second solution). Commented Sep 24, 2014 at 1:29

1 Answer 1

3

One option is using of postwalk-replace:

user> (def foo [1 2 3 
              {:a 1 
               :b 2 
               1  3}])
;; => #'user/foo
user> (postwalk-replace {1 2} foo)
;; => [2 2 3 {2 3, :b 2, :a 2}]

Although, this method has a downside: it replaces all elements in a structure, not only values. This may be not what you want.


Maybe this will do the trick...

(defn my-replace [smap s]
  (letfn [(trns [s]
            (map (fn [x]
                   (if (coll? x)
                       (my-replace smap x)
                       (or (smap x) x)))
                 s))]
    (if (map? s)
      (zipmap (keys s) (trns (vals s)))
      (trns s))))

Works with lists, vectors and maps:

user> (my-replace {1 2} foo)
;; => (2 2 3 {:a 2, :b 2, 1 3})

...Seems to work on arbitrary nested structures too:

user> (my-replace {1 2} [1 2 3 {:a [1 1 1] :b [3 2 1] 1 1}])
;; => (2 2 3 {:a (2 2 2), :b (3 2 2) 1 2})
Sign up to request clarification or add additional context in comments.

3 Comments

OP only wants to replace values. There is also a 1 key that should not be replaced.
@A.Webb, Good point! I'll see if I can come up with something more relevant.
"Only values" is not super well defined. What about an input like {[1 2 3] x, {a 1 b 2} y}? Here the first 1 is not a key, but it is a value inside of a key. And the second 1 is the value in a map, but that map is the key of another map. Are these being replaced? In your edited solution, no. But either way it's pretty weird; I recommend that OP think about whether there's an important reason for map keys to be left untouched.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.