Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pinning list elements to position in a merged list in Scala

This seems like a simple scenario, but I'm stumped on how to solve it elegantly/functionally. I have two lists val pinnedStrings: Seq[(String, Int)] and val fillerString: Seq[Int]. I want to merge them, but with each pinned string guaranteed to be at its paired position in the output list. So if I have:

val pinnedStrings = Seq("apple" -> 1, "banana" -> 4, "cherry" -> 6)
val fillerStrings = Seq("alpha", "bravo", "charlie", "delta", "echo", "foxtrot") 

Then the output should be:

Seq("alpha", "apple", "bravo", "charlie", "banana", "delta", "cherry", "echo", "foxtrot")

Let's say that if there's not enough filler to reach a pinned string, we drop the pinned string. (Or if it's simpler to put all leftover pinned strings at the end, that's fine too.)

like image 977
acjay Avatar asked Nov 28 '25 04:11

acjay


2 Answers

Or:

scala> val pinnedStrings = Seq("apple" -> 1, "banana" -> 4, "cherry" -> 6) 
pinnedStrings: Seq[(String, Int)] = List((apple,1), (banana,4), (cherry,6))

scala> val fillerStrings = Seq("alpha", "bravo", "charlie", "delta", "echo", "foxtrot")
fillerStrings: Seq[String] = List(alpha, bravo, charlie, delta, echo, foxtrot)

scala> (fillerStrings /: pinnedStrings) { case (acc, (s, i)) => ((acc take i) :+ s) ++ (acc drop i) }
res0: Seq[String] = List(alpha, apple, bravo, charlie, banana, delta, cherry, echo, foxtrot)
like image 174
som-snytt Avatar answered Nov 29 '25 22:11

som-snytt


I solved the problem after I'd written up the question, but figured I'd share since I'd already put in the effort:

val pinnedStrings = Seq("apple" -> 1, "banana" -> 4, "cherry" -> 6) 
val fillerStrings = Seq("alpha", "bravo", "charlie", "delta", "echo", "foxtrot") 

// Preadjust the specified indices to account for earlier pinned strings 
val pinnedStringsAdjusted = pinnedStrings.sortBy(_._2).zipWithIndex.map { case ((item, position), index) => (item, position - index) }

// Take advantage of the stability of `sortBy` to give pinned strings priority 
(pinnedStrings ++ fillerStrings.zipWithIndex).sortBy(_._2).map(_._1)

// Output
// res5: Seq[String] = List(alpha, apple, bravo, charlie, banana, delta, cherry, echo, foxtrot)

Should work as intended for adjacent pinned indices but weird behavior would ensue if two pinned strings have matching indices. Open to other options if other people have thoughts as well.

like image 25
acjay Avatar answered Nov 30 '25 00:11

acjay



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!