Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform only the first element of a Scala list

Tags:

list

map

scala

Is there a way to transform only the first element of a list without doing something super hacky like:

val head = l1.head
val tail = l1.tail
val l2   = change(head) :: tail

updated() looks like it could work, but isn't much of an improvement:

val head = l1.head
val l2   = l.update(0, change(head))

I'd love something like:

val l2   = l1.updateHead(change(_))

Is there anything like that?

like image 438
pr1001 Avatar asked May 14 '12 17:05

pr1001


People also ask

How to remove first element of list Scala?

Coming to list, tail() method is used to skip the first element of the list.

Is list immutable in Scala?

Specific to Scala, a list is a collection which contains immutable data, which means that once the list is created, then it can not be altered. In Scala, the list represents a linked list. In a Scala list, each element need not be of the same data type.

How do I convert a list to map in Scala?

To convert a list into a map in Scala, we use the toMap method. We must remember that a map contains a pair of values, i.e., key-value pair, whereas a list contains only single values. So we have two ways to do so: Using the zipWithIndex method to add indices as the keys to the list.


5 Answers

you could try using pattern matching

val l2 = l1 match{
    case Nil   => Nil
    case x::xs => change(x)::xs
}

That way you don't have to worry if head actually returns an element

like image 111
Robert Avatar answered Oct 05 '22 14:10

Robert


You are making your life much harder by introducing variables at every opportunity. Don't do it!

Both of the options you listed are fairly clean if you don't introduce temporary variables:

val l2 = change(l.head) :: l.tail
val l2 = l.update(0, change(l.head))

Neither is entirely safe on empty lists, but

val l2 = l.take(1).map(change) ::: l.drop(1)

is.

You also are always free to enrich list with your own method, however:

class ReheadableList[A](xs: List[A]) {
  def rehead[B >: A](f: A => B) = xs.take(1).map(f) ::: xs.drop(1)
}
implicit def lists_can_be_reheaded[A](xs: List[A]) = new ReheadableList(xs)

(edit--changed to avoid errors with empty lists). Now you can just

val l2 = l.rehead(change)
like image 39
Rex Kerr Avatar answered Oct 05 '22 14:10

Rex Kerr


Using partial lenses (described in this paper), you can write something like:

listHeadLens.set(list, newValue)

where listHeadLens is defined as:

def listHeadLens[A] = new PartialLens[List[A], A] {
  def apply: List[A] => Option[CoState[A, List[A]]] = {
    case Nil => None
    case x :: xs => Some(CoState(x, _ :: xs))
  }
}

I think partial lenses will be making their way to Scalaz 7. I am not sure though.

like image 31
missingfaktor Avatar answered Oct 05 '22 14:10

missingfaktor


There are probably a LOT of ways to do this. Below is a Scala REPL session showing one version

scala> val change = (x: Int) => x*2
change: Int => Int = <function1>

scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)

scala> l.headOption.map( x => change(x) :: l.drop(1) ).getOrElse(Nil)
res3: List[Int] = List(2, 2, 3)
like image 31
Mads Hartmann Avatar answered Oct 05 '22 14:10

Mads Hartmann


You could do it like this.

val list = List("1","2","3")
def change(str : String ) = Some("x")

val nlist = (list.headOption.flatMap(change(_)).toList ::: list.tail)

in the console.

scala> val list = List("1","2","3")
list: List[java.lang.String] = List(1, 2, 3)

scala> def change(str : String ) = Some("x")
change: (str: String)Some[java.lang.String]

scala> val nlist = (list.headOption.flatMap(change(_)).toList ::: list.tail)          
nlist: List[java.lang.String] = List(x, 2, 3)
like image 30
Feargal Avatar answered Oct 05 '22 14:10

Feargal