A dépend de B

Cette semaine, c'est Adrien qui vous propose un #KataOfTheWeek : Expansion de dépendances transitives

Briefing du Kata : Input:L'algorithme prend pour paramètre un ensemble de lignes où le premier mot est le nom d'un objet. Les autres mots de la ligne sont les dépendances directes de l'objet.

Exemple: L'ensemble de dépendances:

  • A dépends de B et D
  • B dépends de C

Est noté:

A B D
B C

Output:La liste complete des dépendances de chaque objets référencés en entrée dans le format que vous voulez.

Exemple:

A: B, C, D
B: C
C:
D:

Test cases:

  • Input:
A B C
B C E
C G
D A F
E F
F H

Output:

H: 
F: H
E: F, H
G: 
C: G
B: C, E, F, G, H
A: B, C, E, F, G, H
D: A, B, C, E, F, G, H
  • Input:
A B
B C
C A

Output:

Circular Dependency

Saurez-vous résoudre le problème ?

Bon courage !


Et voici une solution proposé par l'auteur en Kotlin:

fun expandDependencies(input: String) {
  val dependencies = input.lines()
    .map { line -> line.split("\\s+".toRegex()) }
    .associateBy(
      keySelector = { it.first() },
      valueTransform = { it.drop(1).distinct() }
    )

  val expanded = expandDependencies(dependencies)
  for ((name, deps) in expanded) {
    println("$name: ${deps.joinToString(", ")}")
  }
}

fun expandDependencies(unexpanded: Map<String, List<String>>): Map<String, List<String>> {
  val expanded = mutableMapOf<String, List<String>>()

  val stack = unexpanded.keys.toMutableList()
  val alreadyBumped = mutableSetOf<String>()

  while (stack.isNotEmpty()) {
    val name = stack.removeAt(stack.lastIndex)
    if (name in expanded) continue

    val directDeps = unexpanded[name]
    if (directDeps.isNullOrEmpty()) {
      expanded[name] = emptyList()
      continue
    }

    val unexpandedDeps = directDeps.filter { it !in expanded }
    if (unexpandedDeps.isNotEmpty()) {
      require(unexpandedDeps.none { it in alreadyBumped }) { "Circular dependency for dependency \"$name\"" }
      stack.add(name)
      stack.addAll(unexpandedDeps)
      alreadyBumped.addAll(unexpandedDeps)
      continue
    }

    expanded[name] = directDeps
      .flatMap { expanded.getValue(it) + it }
      .distinct()
      .sorted()
  }

  return expanded
}

Votre équipe TakiVeille