3

I have a list of objects, which contain a list of objects of a same type. E.g.

List[CustomObject(objName, List[CustomObject])]

Currently, I have a program that combines these CustomObjects into a single list. However, they contain all possible "list paths". I want to be able to remove certain paths if they've already been referenced in a longer path.

List(CustomObject("obj-1", List(CustomObject("obj-2", List(CustomObject("obj-3", List())))))

The program outputs all possible paths. For example, it will output in the same list

[obj-1 -> obj-2 ->obj-3,
 obj-1 -> obj-2]

I want to be able to remove the obj-1 -> obj2 because the path is already shown. But I would like to keep that path if further down the path contains different children. For example, the following is desired output where I would rather keep the path. Basically, I want the paths to be unique

[obj-1 -> obj-2-A -> obj -3,
 obj-1 -> obj-2-B -> obj-4]

Requirement: all of the objects will be nested within a single list, not seperate lists.

This has been difficult to explain, so I apologise if it's hard to understand.

EDIT: I'm currently removing any sub-items which are not the longest. However, I do not retain the desired output, because I don't know how to check if a path is totally unique from start to end. If it's not unique from start to end and the entire path is a sub-path of another path, then I want to remove it.

Chris
  • 785
  • 10
  • 24
  • 1
    You say you have a `List` of "all possible paths". What is the data representation of a path? Is a single path a `String`? Is it a `List[String]`? – jwvh Jul 01 '19 at 17:52

1 Answers1

1

Assuming paths are represented as tuples

val l1 =  List(
  ("obj-1", "obj-2", "obj-3"),
  ("obj-1", "obj-2")
)

val l2 =  List(
  ("obj-1", "obj-2", "obj-3"),
  ("obj-1", "obj-2", "obj-4")
)

here is my attempt which depends on finding all indices of startsWith predicate

def removeDuplicateSubpaths(paths: List[Product]): List[Product] = {
  val l = fromTuple(paths)
  l.map { path =>
    l
      .zipWithIndex
      .filter(_._1.startsWith(path))
      .map(_._2)
  }
    .zip(l)
    .filter(_._1.size == 1)
    .map(_._2)
    .map(toTuple)
}

which outputs

removeDuplicateSubpaths(l1) // List((obj-1,obj-2,obj-3))
removeDuplicateSubpaths(l2) // List((obj-1,obj-2,obj-3), (obj-1,obj-2,obj-4))

I reconstitute from and to tuples without knowing arity like so

def fromTuple[T](paths: List[Product]): List[List[T]] =
  paths.map(_.productIterator.toList.asInstanceOf[List[T]])

def toTuple[A](as: List[A]): Product = {
  val tupleClass = Class.forName("scala.Tuple" + as.size)
  tupleClass.getConstructors.apply(0).newInstance(as:_*).asInstanceOf[Product]
}
Mario Galic
  • 47,285
  • 6
  • 56
  • 98