ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

YAML Hierarchical Merge Strategy

YAML

Goal -- WPM

Ready
Exercise Algorithm Area
1package main
2
3import (
4 "fmt"
5 "reflect"
6)
7
8// deepMerge recursively merges two YAML-like structures (maps and lists).
9// It prioritizes values from the second structure (b) in case of conflicts.
10func deepMerge(a, b interface{}) interface{} {
11 // If b is nil, return a (or a copy of a if mutable structures are a concern).
12 if b == nil {
13 return a
14 }
15
16 // If a is nil, return b.
17 if a == nil {
18 return b
19 }
20
21 // Get reflect.Value for both inputs.
22
23 valA := reflect.ValueOf(a)
24 valB := reflect.ValueOf(b)
25
26 // If types are different, b overrides a.
27 if valA.Type() != valB.Type() {
28 return b
29 }
30
31 // Handle maps.
32 if valA.Kind() == reflect.Map {
33 // Create a new map to store the merged result.
34 mergedMap := make(map[string]interface{})
35
36 // Copy all elements from a to mergedMap.
37 for _, key := range valA.MapKeys() {
38 mergedMap[key.String()] = valA.MapIndex(key).Interface()
39 }
40
41 // Iterate over keys in b and merge.
42 for _, key := range valB.MapKeys() {
43 mapKey := key.String()
44 valBElement := valB.MapIndex(key).Interface()
45
46 // If key exists in a, recursively merge.
47 if valAElement, ok := valA.MapIndex(key); ok {
48 mergedMap[mapKey] = deepMerge(valAElement.Interface(), valBElement)
49 } else {
50 // Otherwise, add the element from b.
51 mergedMap[mapKey] = valBElement
52 }
53 }
54 return mergedMap
55 }
56
57 // Handle slices.
58 if valA.Kind() == reflect.Slice {
59 // Create a new slice to store the merged result.
60 mergedSlice := make([]interface{}, 0)
61
62 // Append all elements from a.
63 for i := 0; i < valA.Len(); i++ {
64 mergedSlice = append(mergedSlice, valA.Index(i).Interface())
65 }
66
67 // Append all elements from b.
68 // Note: This simple append strategy might not be ideal for all list merging scenarios.
69 // More complex logic (e.g., based on unique IDs) might be needed.
70 for i := 0; i < valB.Len(); i++ {
71 mergedSlice = append(mergedSlice, valB.Index(i).Interface())
72 }
73 return mergedSlice
74 }
75
76 // For primitive types, b overrides a.
77 return b
78}
79
80func main() {
81 config1 := map[string]interface{}{
82 "service": map[string]interface{}{
83 "name": "api-gateway",
84 "port": 8080,
85 "features": []interface{}{"auth", "logging"},
86 },
87 "database": map[string]interface{}{
88 "type": "postgres",
89 "host": "localhost",
90 },
91 "timeout": 30,
92 }
93
94 config2 := map[string]interface{}{
95 "service": map[string]interface{}{
96 "port": 9090, // Overrides
97 "features": []interface{}{"rate-limiting"}, // Appends to list
98 "version": "v2", // New field
99 },
100 "database": map[string]interface{}{
101 "host": "db.example.com", // Overrides
102 "replica": "db-replica.example.com", // New field
103 },
104 "logging_level": "INFO", // New top-level field
105 }
106
107 mergedConfig := deepMerge(config1, config2)
108
109 // Print the merged configuration (for demonstration)
110 // In a real YAML scenario, you'd marshal this back to YAML.
111 fmt.Printf("%+v\n", mergedConfig)
112
113 // Example with different types
114 config3 := map[string]interface{}{"setting": 100}
115 config4 := map[string]interface{}{"setting": "high"}
116 mergedMixed := deepMerge(config3, config4)
117 fmt.Printf("%+v\n", mergedMixed)
118
119 // Example with nil values
120 config5 := map[string]interface{}{"optional": "present"}
121 config6 := map[string]interface{}{"optional": nil}
122 mergedNil := deepMerge(config5, config6)
123 fmt.Printf("%+v\n", mergedNil)
124
125 config7 := map[string]interface{}{"optional": nil}
126 config8 := map[string]interface{}{"optional": "present"}
127 mergedNil2 := deepMerge(config7, config8)
128 fmt.Printf("%+v\n", mergedNil2)
129}
Algorithm description viewbox

YAML Hierarchical Merge Strategy

Algorithm description:

This function implements a deep merge for hierarchical data structures, commonly found in YAML configuration files. It recursively combines two structures, prioritizing values from the second structure. This is essential for applying environment-specific overrides or merging multiple configuration sources without losing data.

Algorithm explanation:

The `deepMerge` function handles merging of nested maps and slices. It first checks for nil inputs and differing types, where the second input (`b`) always takes precedence. For maps, it creates a new map, copies elements from `a`, and then iterates through `b`. If a key from `b` exists in `a`, it recursively calls `deepMerge` on the values; otherwise, it adds the key-value pair from `b`. For slices, it simply appends all elements from `b` to `a`. This strategy ensures that all configurations are considered, with later configurations overriding or extending earlier ones. The time complexity is roughly O(N*M) in the worst case, where N and M are the total number of elements in the structures, due to recursive calls. Space complexity is also proportional to the size of the merged structure, potentially O(N+M). Edge cases include nil inputs, differing types, and empty maps/slices.

Pseudocode:

function deepMerge(structureA, structureB):
  if structureB is nil:
    return structureA
  if structureA is nil:
    return structureB

  if typeOf(structureA) is not typeOf(structureB):
    return structureB

  if structureA is a map:
    mergedMap = new map
    copy all key-value pairs from structureA to mergedMap
    for each key, valueB in structureB:
      if key exists in structureA:
        valueA = structureA[key]
        mergedMap[key] = deepMerge(valueA, valueB)
      else:
        mergedMap[key] = valueB
    return mergedMap

  if structureA is a list:
    mergedList = new list
    append all elements from structureA to mergedList
    append all elements from structureB to mergedList
    return mergedList

  // For primitive types, structureB overrides structureA
  return structureB