Convert a Scala list to a tuple? - list

How can I convert a list with (say) 3 elements into a tuple of size 3?
For example, let's say I have val x = List(1, 2, 3) and I want to convert this into (1, 2, 3). How can I do this?

You can do it using scala extractors and pattern matching (link):
val x = List(1, 2, 3)
val t = x match {
case List(a, b, c) => (a, b, c)
}
Which returns a tuple
t: (Int, Int, Int) = (1,2,3)
Also, you can use a wildcard operator if not sure about a size of the List
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}

You can't do this in a typesafe way. Why? Because in general we can't know the length of a list until runtime. But the "length" of a tuple must be encoded in its type, and hence known at compile time. For example, (1,'a',true) has the type (Int, Char, Boolean), which is sugar for Tuple3[Int, Char, Boolean]. The reason tuples have this restriction is that they need to be able to handle a non-homogeneous types.

an example using shapeless :
import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled
Note: the compiler need some type informations to convert the List in the HList that the reason why you need to pass type informations to the toHList method

Shapeless 2.0 changed some syntax. Here's the updated solution using shapeless.
import shapeless._
import HList._
import syntax.std.traversable._
val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled
The main issue being that the type for .toHList has to be specified ahead of time. More generally, since tuples are limited in their arity, the design of your software might be better served by a different solution.
Still, if you are creating a list statically, consider a solution like this one, also using shapeless. Here, we create an HList directly and the type is available at compile time. Remember that an HList has features from both List and Tuple types. i.e. it can have elements with different types like a Tuple and can be mapped over among other operations like standard collections. HLists take a little while to get used to though so tread slowly if you are new.
scala> import shapeless._
import shapeless._
scala> import HList._
import HList._
scala> val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil
scala> val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)
scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)

Despite the simplicity and being not for lists of any length, it is type-safe and the answer in most cases:
val list = List('a','b')
val tuple = list(0) -> list(1)
val list = List('a','b','c')
val tuple = (list(0), list(1), list(2))
Another possibility, when you don't want to name the list nor to repeat it (I hope someone can show a way to avoid the Seq/head parts):
val tuple = Seq(List('a','b')).map(tup => tup(0) -> tup(1)).head
val tuple = Seq(List('a','b','c')).map(tup => (tup(0), tup(1), tup(2))).head

FWIW, I wanted a tuple to initalise a number of fields and wanted to use the syntactic sugar of tuple assignment.
EG:
val (c1, c2, c3) = listToTuple(myList)
It turns out that there is syntactic sugar for assigning the contents of a list too...
val c1 :: c2 :: c3 :: Nil = myList
So no need for tuples if you've got the same problem.

If you are very sure that your list.size<23 use it:
def listToTuple[A <: Object](list:List[A]):Product = {
val class = Class.forName("scala.Tuple" + list.size)
class.getConstructors.apply(0).newInstance(list:_*).asInstanceOf[Product]
}
listToTuple: [A <: java.lang.Object](list: List[A])Product
scala> listToTuple(List("Scala", "Smart"))
res15: Product = (Scala,Smart)

You can't do this in a type-safe way. In Scala, lists are arbitrary-length sequences of elements of some type. As far as the type system knows, x could be a list of arbitrary length.
In contrast, the arity of a tuple must be known at compile time. It would violate the safety guarantees of the type system to allow assigning x to a tuple type.
In fact, for technical reasons, Scala tuples were limited to 22 elements, but the limit no longer exists in 2.11 The case class limit has been lifted in 2.11 https://github.com/scala/scala/pull/2305
It would be possible to manually code a function that converts lists of up to 22 elements, and throws an exception for larger lists. Scala's template support, an upcoming feature, would make this more concise. But this would be an ugly hack.

This can also be done in shapeless with less boilerplate using Sized:
scala> import shapeless._
scala> import shapeless.syntax.sized._
scala> val x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.sized(3).map(_.tupled)
res1: Option[(Int, Int, Int)] = Some((1,2,3))
It's type-safe: you get None, if the tuple size is incorrect, but the tuple size must be a literal or final val (to be convertible to shapeless.Nat).

Using Pattern Matching:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}

2015 post.
For the Tom Crockett's answer to be more clarifying, here is a real example.
At first, I got confused about it. Because I come from Python, where you can just do tuple(list(1,2,3)).
Is it short of Scala language ? (the answer is -- it's not about Scala or Python, it's about static-type and dynamic-type.)
That's causes me trying to find the crux why Scala can't do this .
The following code example implements a toTuple method, which has type-safe toTupleN and type-unsafe toTuple.
The toTuple method get the type-length information at run-time, i.e no type-length information at compile-time, so the return type is Product which is very like the Python's tuple indeed (no type at each position, and no length of types).
That way is proned to runtime error like type-mismatch or IndexOutOfBoundException. (so Python's convenient list-to-tuple is not free lunch. )
Contrarily , it is the length information user provided that makes toTupleN compile-time safe.
implicit class EnrichedWithToTuple[A](elements: Seq[A]) {
def toTuple: Product = elements.length match {
case 2 => toTuple2
case 3 => toTuple3
}
def toTuple2 = elements match {case Seq(a, b) => (a, b) }
def toTuple3 = elements match {case Seq(a, b, c) => (a, b, c) }
}
val product = List(1, 2, 3).toTuple
product.productElement(5) //runtime IndexOutOfBoundException, Bad !
val tuple = List(1, 2, 3).toTuple3
tuple._5 //compiler error, Good!

you can do this either
via pattern-matching (what you do not want) or
by iterating through the list and applying each element one by one.
val xs: Seq[Any] = List(1:Int, 2.0:Double, "3":String)
val t: (Int,Double,String) = xs.foldLeft((Tuple3[Int,Double,String] _).curried:Any)({
case (f,x) => f.asInstanceOf[Any=>Any](x)
}).asInstanceOf[(Int,Double,String)]

In scala 3, you can do something like this:
def totuple[A](as: List[A]): Tuple = as match
case Nil => EmptyTuple
case h :: t => h *: totuple(t)
but as has been said already, without giving the compiler any more hard-coded type information, you aren't going to know the length of the tuple or the types of its elements, so this is likely hardly any better than the original list.

as far as you have the type:
val x: List[Int] = List(1, 2, 3)
def doSomething(a:Int *)
doSomething(x:_*)

Related

ZipList with Scalaz

Suppose I have a list of numbers and list of functions:
val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)
Now I would like to use an Applicative to apply f1 to 1, f2 to 2, etc.
val ys: List[Int] = xs <*> fs // expect List(f1(1), f2(2), f3(3))
How can I do it with Scalaz ?
pure for zip lists repeats the value forever, so it's not possible to define a zippy applicative instance for Scala's List (or for anything like lists). Scalaz does provide a Zip tag for Stream and the appropriate zippy applicative instance, but as far as I know it's still pretty broken. For example, this won't work (but should):
import scalaz._, Scalaz._
val xs = Tags.Zip(Stream(1, 2, 3))
val fs = Tags.Zip(Stream[Int => Int](_ + 3, _ + 2, _ + 1))
xs <*> fs
You can use the applicative instance directly (as in the other answer), but it's nice to have the syntax, and it's not too hard to write a "real" (i.e. not tagged) wrapper. Here's the workaround I've used, for example:
case class ZipList[A](s: Stream[A])
import scalaz._, Scalaz._, Isomorphism._
implicit val zipListApplicative: Applicative[ZipList] =
new IsomorphismApplicative[ZipList, ({ type L[x] = Stream[x] ## Tags.Zip })#L] {
val iso =
new IsoFunctorTemplate[ZipList, ({ type L[x] = Stream[x] ## Tags.Zip })#L] {
def to[A](fa: ZipList[A]) = Tags.Zip(fa.s)
def from[A](ga: Stream[A] ## Tags.Zip) = ZipList(Tag.unwrap(ga))
}
val G = streamZipApplicative
}
And then:
scala> val xs = ZipList(Stream(1, 2, 3))
xs: ZipList[Int] = ZipList(Stream(1, ?))
scala> val fs = ZipList(Stream[Int => Int](_ + 10, _ + 11, _ + 12))
fs: ZipList[Int => Int] = ZipList(Stream(<function1>, ?))
scala> xs <*> fs
res0: ZipList[Int] = ZipList(Stream(11, ?))
scala> res0.s.toList
res1: List[Int] = List(11, 13, 15)
For what it's worth, it looks like this has been broken for at least a couple of years.
I see a solution with streamZipApplicative :
import scalaz.std.stream._
import scalaz.Tags
val xs: List[Int] = List(1, 2, 3)
val fs: List[Int => Int] = List(f1, f2, f3)
val zippedLists = streamZipApplicative.ap(Tags.Zip(xs.toStream)) (Tags.Zip(fs.toStream))
val result = Tag.unwrap(zippedLists).toList
Learning Scalaz spends a few paragraphs on this topic in their introduction to Applicatives. They quote LYAHFGG:
However, [(+3),(2)] <> [1,2] could also work in such a way that the first function in the left list gets applied to the first value in the right one, the second function gets applied to the second value, and so on. That would result in a list with two values, namely [4,4]. You could look at it as [1 + 3, 2 * 2].
But then adds:
This can be done in Scalaz, but not easily.
The "not easily" part uses streamZipApplicative like in #n1r3's answer:
scala> streamZipApplicative.ap(Tags.Zip(Stream(1, 2)))(Tags.Zip(Stream({(_: Int) + 3}, {(_: Int) * 2})))
res32: scala.collection.immutable.Stream[Int] with Object{type Tag = scalaz.Tags.Zip} = Stream(4, ?)
scala> res32.toList
res33: List[Int] = List(4, 4)
The "not easily" is the part that bothers me. I'd like to borrow from #Travis Brown fantastic answer. He is comparing the use of monads and applicatives (i.e. why use applicatives when you have a monad?):
Second (and relatedly), it's just a solid development practice to use the least powerful abstraction that will get the job done.
So, I would say that until a framework provides an applicative that works like your first use-case:
val ys: List[Int] = xs <*> fs
To use zip and map here instead:
xs.zip(fs).map(p=>p._2.apply(p._1))
To me, this code is much clearer and simpler than the alternatives in scalaz. This is the least powerful abstraction that gets the job done.

Arithmetic operations on list with missing values

I'm trying to do some arithmetic on a list that may contain missing values.
So far, I'm representing my list with Option[Int]:
val mylist=List( Option(4), Option(8), None )
With this representation, I can easily apply a function over the list (say, multiply by 2):
scala> mylist.map(_.map(_*2))
res2: List[Option[Int]] = List(Some(8), Some(16), None)
However, this looks more complicated than it needs be, so I'm wondering if I'm missing something.
Also, I can't figure out how to write things like the sum. I guess it should be possible with a (big) reduce expression...
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
Well, it's not a pattern I've used myself, but if values can be "missing" then an Option is appropriate. But a List probably isn't. In a List the position isn't usually something you should be relying on, since it's not random-access. Maybe a Vector would be better, or you need to think of a better way of modelling your problem, i.e. not as a list with missing values.
You can deal with Option nicely using for-expressions:
for (o <- mylist; x <- o) yield x * 2
or flatten the list:
mylist.flatten.map(_ * 2)
To sum it:
mylist.flatten.sum
List[Option[Int]] is a good representation for this use case
Is it possible to flatten it earlier with flatMap? For example, if you are creating this list using map, you could use flatMap instead and not have missing values. My suggestion is to not even represent the missing values if possible. If you need to represent them, Option is ideal.
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
The nested map is probably preferable. You can foldLeft also.
foldLeft is also helpful if you need to do something besides sum/product.
scala> val mylist=List( Option(4), Option(8), None )
mylist: List[Option[Int]] = List(Some(4), Some(8), None)
scala> mylist.foldLeft(0){
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res7: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res8: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc - (i * 2)
| case (acc, _) => acc
| }
res16: Int = -24
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
Option is definitely the preferable way to express missing values. You could also think about changing it into a List[(Int, Int)] where the first element indicates the position in your original list and the second element represents the value.
mylist.map(_.map(_*2)) is the best way to map
In my opinion there is no shorter or cleaner way to express that. (You have two "levels" that's why you need two maps!) With my suggested data structure this would turn into mylist.map(t => (t._1, t._2*2)).
is there a simple way to do a sum?
No easier way than om-nom-nom suggested. With my data structure it would be mylist.map(_._2).sum
The most general and most concise way to do this is with Scalaz's semigroup type class. That way, you're not restricted to List[Option[Int]] but can apply the same function to List[Int].
import scalaz._
import Scalaz._
object S {
def double[A:Semigroup](l:List[A]) = l.map(x => x |+| x)
def sum[A:Semigroup](l:List[A]) = l.reduce(_ |+| _)
def main(a:Array[String]) {
val l = List(Some(1), None, Some(2))
val l2 = List(1,2)
println(double(l))
println(sum(l))
println(double(l2))
println(sum(l2))
}
}
This prints
List(Some(2), None, Some(4))
Some(3)
List(2, 4)
3
i'm not sure what it is you are trying to achieve, but this does'nt seem like the right approach. if you need to determine if a value exists in your "list", then perhapse a Set would suit your needs better:
scala> val s = Set(4,8)
s: scala.collection.immutable.Set[Int] = Set(4, 8)
scala> s(4)
res0: Boolean = true
scala> s(5)
res1: Boolean = false
scala> s map (_ * 2)
res2: scala.collection.immutable.Set[Int] = Set(8, 16)
scala> s reduceLeft((a,b) => a+b)
res3: Int = 12
or even easier:
scala> s sum
res4: Int = 12
if you need something more sophisticated, and the index of the element in your list is important, you may use a Map where the keys simulate the index, and missing values can be mapped to some default value:
scala> val m = Map(1 -> 4, 2 -> 8) withDefault(n => 0)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 2 -> 8)
scala> m(1)
res5: Int = 4
scala> m(3)
res6: Int = 0
scala> m map {case (k,v) => (k,2*v)}
res7: scala.collection.immutable.Map[Int,Int] = Map(1 -> 8, 2 -> 16)
scala> m.foldLeft(0){case (sum,(_,v)) => sum+v}
res8: Int = 12
again, not sure what your needs are, but it feels like you are going the wrong way...
Option is a type i would think twice before using. ask yourself if it's realy necessary. there might be solutions that would achieve what you are trying to do in a more elegant way.

scala zip list to tuple

Working with JodaTime, trying to convert a List[LocalDate] to Tuple2[JodaTime, JodaTime] so I can do multi-assigment like so:
val(expire, now) =
List(row.expireDate, new JodaDate) zip (_.toDateTimeAtStartOfDay.getMillis)
which of course does not compile. Is there a similarly concise way to do the above? I know I can just do it manually:
val(expire, now) =
(row.expireDate.toDateTimeAtStartOfDay.getMillis,
new JodaDate().toDateTimeAtStartOfDay.getMillis)
but that's a bit ugly
val Seq(expire, now) =
Seq(row.expireDate, new JodaDate).map(_.toDateTimeAtStartOfDay.getMillis)
What you want (assuming you don't want to go the conversion-to-Seq route) is Scalaz's Bifunctor instance for tuples (which isn't in the standard library). With it you can write the following:
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> val cap = (_: String).toUpperCase
cap: String => java.lang.String = <function1>
scala> val removeLs = (_: String).replaceAll("l", "")
removeLs: String => java.lang.String = <function1>
scala> cap <-: ("hello", "world") :-> removeLs
res0: (java.lang.String, java.lang.String) = (HELLO,word)
Or, in your case:
val f = (_: JodaDate).toDateTimeAtStartOfDay.getMillis
val (expire, now) = f <-: (row.expireDate, new JodaDate) :-> f
val Seq(a, b) =
Seq("a", "b").map(_.toUpperCase)
println("a, b = %s, %s".format(a, b)) // a, b = A, B
If you want to keep the type safety of using a tuple (remember, when unapplying a Seq, the compiler will not check the length), you can write a wrapper to add a function not available in the standard library, which will let you map over a tuple.
In the case of mapping over both elements using a single function, because a Tuple2[A, B] has two type parameters, the key to making this work is to require evidence that A and B are the same type. To do this, require an implicit parameter of type B =:= A; if the types are indeed equal, the compiler will supply a function of type B => A.
class Tuple2Wrapper[A, B](t: (A, B)) {
def bimap[C, D](f: A => C, g: B => D): (C, D) = (f(t._1), g(t._2))
def <-:->[C](f: A => C)(implicit ev: B =:= A): (C, C) = bimap(f, f compose ev)
}
implicit def tuple2Tuple2Wrapper[A, B](t: (A, B)) = new Tuple2Wrapper(t)
scala> (1, 1) <-:-> (_ + 1)
res1: (Int, Int) = (2,2)
This could be done in a more general and useful way (applicable to more types than just Tuple2), if implemented in terms of Scalaz's Bifunctor trait.

Scala: alternative List syntax (with square brackets, if possible)

is there an alternative 'List' syntax in Scala?
Is it possible to define one aditional class/type/operator* called '[' and ']'?
I know 'square brackets' are used to indicate Type, but they are perfect to the repetitive task of declaring lists.
A ';' or '?' would be good also, as a last resource.
Thanks
obs.:
after much search the only alternative I found was to use 'cons':
val list = 1 :: 2 :: 3 :: Nil
but it doesn't reduce any key typing at all.
I am still learning those things in Scala
EDIT:
Just to clarify: Performance is not a priority in my case. And yes, shift is not welcome. :P
Motivation behind the scenes: I like Haskell style, but cannot use it directly with Java.
EDIT 2:
Final solution based on both Rex Kerr solutions
implementing object Types:
package a
object Types {
type \[z] = List[z]
implicit def make_lists[A](z: A) = new ListMaker(z)
class ListMaker[A](a0: A) {
private[this] val buffer = List.newBuilder[A]
buffer += a0
def \(z: A) = {
buffer += z;
this
}
def \\ = buffer.result
}
}
using object Types:
package a
import a.Types._
object Whatever {
def listInListOut (l: \[Int]) = {
1\2\\
}
}
[ and ] are reserved symbols in Scala which are used for type annotations. You can't use them for lists. ; is reserved for end of line. You could use ? in many cases, but it would be awkward.
I recommend that you learn to use the :: notation (and get used to typing the : symbol fast twice in succession) because it really makes the list operations visually clear, plus it is a great syntactic reminder that lists are weird because you put things on the head of the list.
However, if you cannot tolerate this, your best option is probably to define a one-letter list symbol. For example,
List(1,2,3,4)
is a list of the numbers from 1 to 4. What if you could just type L instead of List? It turns out that you can, since this is not a fancy constructor or static method, but a singleton companion object to the class List. So you just
val L = List
L(1,2,3,4)
and you are just one character worse off than your suggestion of brackets.
Define
def l[A](a:A*) = List(a:_*)
Then you can do
l(1,2,3)
which is only one character more than [1,2,3]
I can't help pointing out another way to go here for lists where all the elements are the same type, if you really hate the shift key and don't care if other people can understand your code:
class ListMaker[A](a0: A) {
private[this] val buffer = List.newBuilder[A]
buffer += a0
def \(a: A) = { buffer += a; this }
def \\ = buffer.result
}
implicit def make_lists[A](a: A) = new ListMaker(a)
Now you can list to your heart's content, without ever touching the shift key!
scala> val a = 1\2\3\4\5\\
a: List[Int] = List(1, 2, 3, 4, 5)
scala> val b = 'a'\'b'\\
b: List[Char] = List(a, b)
scala> val c = false\true\false\false\false\false\true\\
c: List[Boolean] = List(false, true, false, false, false, false, true)
This uses exactly as many characters as brackets would. (It doesn't nest well, however.)
Welcome to Scala version 2.10.0.r24777-b20110419020105 (Java HotSpot(TM) Client VM, Java 1.6.0
Type in expressions to have them evaluated.
Type :help for more information.
scala> class LM[A](x: A) {
| def \(y: A) = List(x,y)
| }
defined class LM
scala> implicit def a2l[A](x: A): LM[A] = new LM(x)
a2l: [A](x: A)LM[A]
scala> class LX[A](xs: List[A]) {
| def \(y: A) = xs:::List(y)
| }
defined class LX
scala> implicit def l2lx[A](xs: List[A]): LX[A] = new LX(xs)
l2lx: [A](xs: List[A])LX[A]
scala> 1\2
res0: List[Int] = List(1, 2)
scala> 1\2\3
res1: List[Int] = List(1, 2, 3)
scala>
Not exactly an alternative syntax, but it is by far the most portable solution:
In Intellij IDEA it is possible to create "Live Templates";
press Ctrl+Alt+s; search for "template"; go to "Live Templates" section;
just add one new item named "l" inside Scala entry, add a random description and the following code:
List($END$)
Press Enter, go to the editor, press L followed by Tab.
It is the end of your typing pains.
Do the same for Arrays.

How to replace a given item in a list?

This describes the problem pretty well:
scala> var l2 = List(1,2,3)
l2: List[Int] = List(1, 2, 3)
scala> l2(2) = 55
<console>:10: error: value update is not a member of List[Int]
l2(2) = 55
^
scala.List is immutable, meaning you cannot update it in place. If you want to create a copy of your List which contains the updated mapping, you can do the following:
val updated = l2.updated( 2, 55 )
There are mutable ordered sequence types as well, in scala.collection.mutable, such as Buffer types which seem more like what you want. If you try the following you should have more success:
scala> import scala.collection._
import scala.collection._
scala> val b = mutable.Buffer(1,2,3)
b: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
scala> b(2) = 55
scala> b
res1: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 55)
Edit: Just to note that some other answers have mentioned that you should use a "mutable List type" - this is true, but "List" in Scala just refers to the single-linked list, whereas in Java it's generally used for any ordered, random-access collection. There is also a DoubleLinkedList, which is more like a Java LinkedList, and a MutableList, which is a type used for the internals of some other types.
Generally speaking what you probably want in Scala is a Buffer for this job; especially since the default implementation is an ArrayBuffer, which is pretty close to being the same as ArrayList, most peoples' default, in Java.
If you ever want to find out what the closest "mapping" of a Java collections interface to the Scala world is, though, the easiest thing to do is probably just check what JavaConversions does. In this case you can see the mapping is to Buffer:
scala.collection.mutable.Buffer <=> java.util.List
The List you are creating is immutable.
scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> l.getClass
res3: java.lang.Class[_] = class scala.collection.immutable.$colon$colon
Use a mutable List instead and you should be fine.
But you can wrap the assignment in an implicit if you don't like updated
implicit class RichList[A](l: List[A]) {
def update(which: Int, what: A): List[A] = {
l.updated(which, what)
}
}
val l = List(1, 2, 3)
val l2 = l(2) = 55
List(1, 2, 55)
Your problem is that Lists in scala are immutable, you need to use a mutable list instead.
Import scala.collection.mutable.Queue and use that instead. Queue is a MutableList, so it should do what you want.
Lists are immutable in scala. But if you want to replace an element in a List you can use "updated" method like this
val num:List[Int]=List(1,5,4,7,8,2,10)
num=num.updated(0,22)
Since Lists are immutable,this creates a copy of the first List called num(as we assigned the new list to 'num') by replacing 0th element to 22.So the genaral updated method is
listname.updated(index,value)