How can I idiomatically "remove" a single element from a list in Scala and close the gap?

This is the use case of filter:

scala> List(1,2,3,4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)

scala> res0.filter(_ != 2)
res1: List[Int] = List(1, 3, 4, 5)

You want to use map when you are transforming all the elements of a list.


To answer your question directly, I think you're looking for patch, for instance to remove element with index 2 ("c"):

List("a","b","c","d").patch(2, Nil, 1)      // List(a, b, d)

where Nil is what we're replacing it with, and 1 is the number of characters to replace.

But, if you do this:

I have four lists that are associated with each other by index; one list stores the course names, one stores the time the class begins in a simple int format (ie 130), one stores either "am" or "pm", and one stores the days of the classes by int

you're going to have a bad time. I suggest you use a case class:

case class Course(name: String, time: Int, ampm: String, day: Int)

and then store them in a Set[Course]. (Storing time and days as Ints isn't a great idea either - have a look at java.util.Calendar instead.)


First a few sidenotes:

  1. List is not an index-based structure. All index-oriented operations on it take linear time. For index-oriented algorithms Vector is a much better candidate. In fact if your algorithm requires indexes it's a sure sign that you're really not exposing Scala's functional capabilities.

  2. map serves for transforming a collection of items "A" to the same collection of items "B" using a passed in transformer function from a single "A" to single "B". It cannot change the number of resulting elements. Probably you've confused map with fold or reduce.

To answer on your updated question

Okay, here's a functional solution, which works effectively on lists:

val (resultCourses, resultTimeList, resultAmOrPmList, resultDateList)
  = (courses, timeList, amOrPmList, dateList)
      .zipped
      .filterNot(_._1 == input)
      .unzip4

But there's a catch. I actually came to be quite astonished to find out that functions used in this solution, which are so basic for functional languages, were not present in the standard Scala library. Scala has them for 2 and 3-ary tuples, but not the others.

To solve that you'll need to have the following implicit extensions imported.

implicit class Tuple4Zipped 
  [ A, B, C, D ] 
  ( val t : (Iterable[A], Iterable[B], Iterable[C], Iterable[D]) ) 
  extends AnyVal 
  {
    def zipped 
      = t._1.toStream
          .zip(t._2).zip(t._3).zip(t._4)
          .map{ case (((a, b), c), d) => (a, b, c, d) }
  }

implicit class IterableUnzip4
  [ A, B, C, D ]
  ( val ts : Iterable[(A, B, C, D)] )
  extends AnyVal
  {
    def unzip4
      = ts.foldRight((List[A](), List[B](), List[C](), List[D]()))(
          (a, z) => (a._1 +: z._1, a._2 +: z._2, a._3 +: z._3, a._4 +: z._4)
        )
  }

This implementation requires Scala 2.10 as it utilizes the new effective Value Classes feature for pimping the existing types.

I have actually included these in a small extensions library called SExt, after depending your project on which you'll be able to have them by simply adding an import sext._ statement.

Of course, if you want you can just compose these functions directly into the solution:

val (resultCourses, resultTimeList, resultAmOrPmList, resultDateList)
  = courses.toStream
      .zip(timeList).zip(amOrPmList).zip(dateList)
      .map{ case (((a, b), c), d) => (a, b, c, d) }
      .filterNot(_._1 == input)
      .foldRight((List[A](), List[B](), List[C](), List[D]()))(
        (a, z) => (a._1 +: z._1, a._2 +: z._2, a._3 +: z._3, a._4 +: z._4)
      )