96

First map is default options [a: true, b: false]. Second map - options passed by user [a:false]. Does Groovy has maps merge method to obtain [a: false, b:false]?

It's not problem to implement it in Groovy. I'm asking about method out of the box

Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
fedor.belov
  • 22,343
  • 26
  • 89
  • 134

2 Answers2

192

You can use plus:

assert [ a: true, b: false ] + [ a: false ] == [ a: false, b: false ]

Or left shift:

assert [ a: true, b: false ] << [ a: false ] == [ a: false, b: false ] 

The difference is that << adds the right hand map into the left hand map. When you use +, it constructs a new Map based on the LHS, and adds the right hand map into it

Joshua Webb
  • 646
  • 1
  • 11
  • 21
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • 1
    Also maybe worth noting that when you can use `+`, you can also use `+=`: `def m1 =[ a: true, b: false ]; m1 += [ a: false ] ; println (m1 == [ a: false, b: false ])` – Patrice M. Nov 16 '20 at 17:28
1

It's possible to use Map.withDefault(Closure) Groovy Enhancement method or the Spread operator (*), besides using the plus (+) and left shift (<<) operators:

Map.withDefault(Closure init)

def defaults = [ a: true, b: false, ]
def args = [ a: false, ]
def options = args.withDefault { defaults[it] }

assert options == [ a: false ]
assert [ options["a"], options["b"] ] == [ false, false ]
assert options == [ a: false, b: false ]

Map.withDefault wraps a map using the decorator pattern with a wrapper that intercepts all calls to get(key). If an unknown key is found, a default value will be stored into the Map before being returned. The default value stored will be the result of calling the supplied Closure with the key as the parameter to the Closure.

If you have a requirement that every boolean in the Map has the same value by default, then you could write the following:

def args = [ a: true, ]
def options = args.withDefault { false }

assert options == [ a: true ]
assert [ options["a"], options["b"], options["c"] ] == [ true, false, false ]
assert options == [ a: true, b: false, c: false ]

Spread Operator (*)

def defaults = [ a: true, b: false, ]
def args = [ a: false, ]

assert [ foo: "bar", *: defaults, *: args, ] == [ a: false, b: false, foo: "bar" ]

Roughly similar to the plus operator but works only on map literals.

Plus Operator (+)

assert [ a: true, b: false ] + [ a: false ] == [ a: false, b: false ]

Roughly equivalent to Map m = new HashMap(); m.putAll(left); m.putAll(right); return m;.

Left Shift Operator (<<)

assert [ a: true, b: false ] << [ a: false ] == [ a: false, b: false ] 

Roughly equivalent to left.putAll(right); return left;.


Also, you could get the default value by demand in a wrapper function similar to what Map.withDefault does:

Map.get(Object key, Object defaultValue)

def defaults = [ a: true, b: false, ]
def args = [ a: false, ]
assert args.get("a", defaults["a"]) == false
assert args.get("b", defaults["b"]) == false

For a method which doesn't mutate the map, consider instead using Map#getOrDefault(Object, Object) or consider using Groovy's MapWithDefault.

  • Plus and Shift operator sections were inspired by Tim Yates' answer.
  • Checkout Groovy's Enhancement Map documentation for better understanding.
Maicon Mauricio
  • 2,052
  • 1
  • 13
  • 29