I have a Vector
and I'd like to find neighbors of given element.
Say if we have Vector(1, 2, 3, 4, 5)
and then:
- for element
2
, result must beSome((1, 3))
- for element
5
, result must beSome((4, 1))
- for element
1
, result must beSome((5, 2))
- for element
6
, result must beNone
and so on..
I have not found any solution in standard lib(please point me if there is one), so got the next one:
implicit class VectorOps[T](seq: Vector[T]) {
def findNeighbors(elem: T): Option[(T, T)] = {
val currentIdx = seq.indexOf(elem)
val firstIdx = 0
val lastIdx = seq.size - 1
seq match {
case _ if currentIdx == -1 || seq.size < 2 => None
case _ if seq.size == 2 => seq.find(_ != elem).map(elem => (elem, elem))
case _ if currentIdx == firstIdx => Some((seq(lastIdx), seq(currentIdx 1)))
case _ if currentIdx == lastIdx => Some((seq(currentIdx - 1), seq(firstIdx)))
case _ => Some((seq(currentIdx - 1), seq(currentIdx 1)))
}
}
}
The question is: how this can be simplified/optimized using stdlib?
CodePudding user response:
def neighbours[T](v: Seq[T], x: T): Option[(T, T)] =
(v.last : v : v.head)
.sliding(3, 1)
.find(_(1) == x)
.map(x => (x(0), x(2)))
This uses sliding
to create a 3 element window in the data and uses find
to match the middle value of the 3. Adding the last/first to the input deals with the wrap-around case.
This will fail if the Vector
is too short so needs some error checking.
CodePudding user response:
Optimal when number of calls with the same sequence is about or more than seq.toSet.size:
val elementToPair = seq.indicies.map(i => seq(i) ->
(seq((i - 1 seq.length) % seq.length), seq((i 1 seq.length) % seq.length)
).toMap
elementToPair.get(elem)
// other calls
Optimal when number of calls with the same sequence less than seq.toSet.size:
Some(seq.indexOf(elem)).filterNot(_ == -1).map { i =>
(seq((i - 1 seq.length) % seq.length), seq((i 1 seq.length) % seq.length) }