3

I have sequences:

val A = Seq(1,3,0,4,2,0,7,0,6)
val B = Seq(8,9,10)

I need a new sequence where 0 are replaced with values from second sequence:

Seq(1,3,8,4,2,9,7,10,6)

How to do that in functional style?

codez
  • 1,381
  • 1
  • 18
  • 28

3 Answers3

8

You can use map here, by replacing all 0s with the next element of b (by converting b to an iterator, and using next):

val a = Seq(1,3,0,4,2,0,7,0,6)
val b = Seq(8,9,10).iterator
a.map { e => if (e == 0) b.next else e } //Seq(1,3,8,4,2,9,7,10,6)
Ben Reich
  • 16,222
  • 2
  • 38
  • 59
4

Not sure that iterators are really functional. Anyway, here's an alternative

val A = Seq(1,3,0,4,2,0,7,0,6)  
val B = Seq(8,9,10)              
A.foldLeft((B, Seq[Int]())) {case ((b, r), e) => 
          if (e == 0 && ! b.isEmpty) (b.tail, b.head +: r) else (b, e +: r) }
   ._2.reverse
//> res0: Seq[Int] = List(1, 3, 8, 4, 2, 9, 7, 10, 6)

EDIT: Updated per the comment to leave the zeros if we're out of elements of B

EDIT2:

A pattern-matching variant is neater:

A.foldLeft((B, Seq[Int]())){case ((h +: t, r), 0) =>  (t, h +: r)
                            case ((b, r), e) => (b, e +: r)}
 ._2.reverse

And, based on what is proper monad or sequence comprehension to both map and carry state across?

A.mapAccumLeft(B, { case ((h +: t), 0) =>  (t, h)
                    case (b, e)  => (b, e) }

(probably, I don't have scalaz installed to test it)

Community
  • 1
  • 1
The Archetypal Paul
  • 41,321
  • 20
  • 104
  • 134
2

If you want to look at Tail Recursion then this suits you.

@annotation.tailrec
  def f(l1: Seq[Int], l2: Seq[Int], res: Seq[Int] = Nil): Seq[Int] = {
    if (l1 == Nil) res
    else {
      if (l1.head == 0 && l2 != Nil) f(l1.tail, l2.tail, res :+ l2.head)
      else
        f(l1.tail, l2, res :+ l1.head)
    }
  }

val A = Seq(1, 3, 0, 4, 2, 0, 7, 0, 6)
val B = Seq(8, 9, 10)

scala> f(A,B)
res0: Seq[Int] = List(1, 3, 8, 4, 2, 9, 7, 10, 6)

if you run out of elements in B then ,

val A = Seq(1, 3, 0, 4, 2, 0, 7, 0, 6)
val B = Seq(8, 9)
scala> f(A,B)
res1: Seq[Int] = List(1, 3, 8, 4, 2, 9, 7, 0, 6)

if elements in A are less than B then,

val A = Seq(1, 0)
val B = Seq(8, 9, 10)
scala> f(A,B)
res2: Seq[Int] = List(1, 8)
curious
  • 2,908
  • 15
  • 25