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

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.

Related

Fetch elements from Option[Any] of List

scala> val a = jsonMap.get("L2_ID")
a: Option[Any] = Some(List(24493, 22774, 23609, 20517, 22829, 23646, 22779, 23578, 22765, 23657))
I want to fetch the first element of list i.e 24493. So, tried below code:
scala> var b = a.map(_.toString)
b: Option[String] = Some(List(24493, 22774, 23609, 20517, 22829, 23646, 22779, 23578, 22765, 23657))
scala>
scala> var c = b.map(_.split(",")).toList.flatten
c: List[String] = List(List(24493, " 22774", " 23609", " 20517", " 22829", " 23646", " 22779", " 23578", " 22765", " 23657)")
scala> c(0)
res34: String = List(24493
This is not returning as expected.
I suggest you use pattern matching.
To be defensive, i also added a Try to protect against the case of your json not being a List of numbers.
Code below returns an Option[Int] and you can call .getOrElse(0) on it - or some other default value, if you like.
import scala.util.Try
val first = a match {
case Some(h :: _) => Try(h.toString.toInt).toOption
case _ => None
}
So, you have an Option, and List inside of it. Then scala> var b = a.map(_.toString) converts the contents of the Option (a List) into a String. That's not what you want.
Look at the types of the results of your transformations, they are there to provide pretty good hints for you. b: Option[String], for example, tells you that you have lost the list ...
a.map(_.map(_.toString))
has the type Option[List[String]] on the other hand: you have converted every element of the list to a string.
If you are just looking for the first element, there is no need to convert all of them though. Something like this will do:
a
.flatMap(_.headOption) // Option[Int], containing first element or None if list was empty or id a was None
.map(_.toString) // convert Int inside of Option (if any) to String
.getOrElse("") // get the contents of the Option, or empty string if it was None
If you are certain that it's a Some, and that the list is non-empty, then you can unwrap the option and get the List[Int] using .get. Then you can access the first element of the list using .head:
val x: Option[List[Int]] = ???
x.get.head
If you are not in the REPL, and if you aren't sure whether it's a Some or None, and whether the List has any elements, then use
x.flatMap(_.headOption).getOrElse(yourDefaultValueEg0)
"Stringly-typed" programming is certainly not necessary in a language with such a powerful type system, so converting everything to string and splitting by commas was a seriously flawed approach.

(Scala) Keeping the structure of a list in the output

I need a little assistance.
I've been working out the functional aspects in Scala. Almost all the work is in lists and for the most part, I can work out the problems, but I hit a small dead-end. I can't keep the original form (structure) of the list in certain problems. In the output all the nested lists get flattened. Concatenate ::: flattens the list(that is an element of the original list) and append :: gives me a compilation error, as it requires a generic T type (not a list).
A very simple example, in which I want to remove the first element of a list that matches the input:
def removeFirst[T](obj: T, list: List[T]): List[T] = {
if (list isEmpty) Nil
else{
val fin: List[T] = list.head match {
case headAsList: List[T] => if (containsWithNestedLists(obj, headAsList))
removeFirst(obj, headAsList) ::: list.tail
else headAsList ::: removeFirst(obj, list.tail)
case _ => if (list.head == obj) list.tail
else if (list.tail == List()) List(list.head)
else list.head :: removeFirst(obj, list.tail)
}
fin
}
}
For one level deep lists, it works fine, but
the output that comes out for
removeFirst(1,List(List(1,2,3),1,2,3,4,5,6)) is List(2, 3, 1, 2, 3, 4, 5, 6), where as ideally I would want List(List(2,3),1,2,3,4,5,6)).
Or the more specific input removeFirst(1,List(List(2,3,List()),List(1,2,3),1,2,3,4,5,6,List(2,3,List())))
should have output = List(List(2,3,List()),List(2,3),1,2,3,4,5,6,List(1,2,3,List()))
Also I have found that removing the generic T and using Any in its place does the trick, but I also know that Any is a big no-no and a temporary solution for a permanent problem, as in other functions it hasn't helped.
As far as I know, I haven't seen a helpful solution on the internet, so I have to ask. Am I missing something, need to debug or is there another function that could help me? The closest I've come to my answer is using append :: in some manner, but I may be wrong.
You examples just look as if you want to remove a certain element from the list if it is present.
For flat lists you can do this much simpler:
def removeFirst[T](obj: T, list: List[T]) = list match {
case `obj` :: rest => rest
case _ => list
}
This will do the following:
> removeFirst(1, List(1, List(1,2,3)))
res57: List[Any] = List(List(1, 2, 3))
> removeFirst(1, List(2, List(1,2,3)))
res58: List[Any] = List(2, List(1, 2, 3))
> removeFirst(List(2,3), List(List(2,3), List(1,2,3)))
res59: List[List[Int]] = List(List(1, 2, 3))
However, it seems you want to do this for arbitrarily nested Lists. This is not directly possible, as Scala cannot express the exact type of that. The type you'd need would be something like
type NestedList[T] = List[T union NestedList[T]]
Scala does not have union types and you cannot do recursive definitions in this way, so you can not just do this either:
type NestedList[T] = List[Either[T, NestedList[T]]]
You can however do it, if you use a class instead of a type:
case class NestedList[T](value: List[Either[T, NestedList[T]]])
Now you can write your algorithm like this:
def removeFirst[T](obj: T, list: NestedList[T]): NestedList[T] = {
val rest = list.value match {
case Left(`obj`) :: tail => tail
case __ => list.value
}
NestedList(rest.map {
case Right(r) => Right(removeFirst(obj, r))
case Left(r) => Left(r)
})
}
And you can do this:
> removeFirst(1, NestedList(List(Left(1), Left(2), Right(NestedList(List(Left(1),Left(3)))))))
res71: NestedList[Int] = NestedList(List(Left(2), Right(NestedList(List(Left(3))))))
It is of course a bit cumbersome to build and decompose these structures. So maybe it would be better to build a proper tree class using a sealed abstract class and two case classes instead of using the Either.

Convert a Scala list to a tuple?

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:_*)

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)

scala return on first Some in list

I have a list l:List[T1] and currently im doing the following:
myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)
The myfun function returns None or Some, flatten throws away all the None's and find returns the first element of the list if any.
This seems a bit hacky to me. Im thinking that there might exist some for-comprehension or similar that will do this a bit less wasteful or more clever.
For example: I dont need any subsequent answers if myfun returns any Some during the map of the list l.
How about:
l.toStream flatMap (myfun andThen (_.toList)) headOption
Stream is lazy, so it won't map everything in advance, but it won't remap things either. Instead of flattening things, convert Option to List so that flatMap can be used.
In addition to using toStream to make the search lazy, we can use Stream::collectFirst:
List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None
This:
Transforms the List into a Stream in order to stop the search early.
Transforms elements using myFun as Option[T]s.
Collects the first mapped element which is not None and extract it.
Starting Scala 2.13, with the deprecation of Streams in favor of LazyLists, this would become:
List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }
Well, this is almost, but not quite
val x = (l flatMap myfun).headOption
But you are returning a Option rather than a List from myfun, so this may not work. If so (I've no REPL to hand) then try instead:
val x = (l flatMap(myfun(_).toList)).headOption
Well, the for-comprehension equivalent is pretty easy
(for(x<-l, y<-myfun(x)) yield y).headOption
which, if you actually do the the translation works out the same as what oxbow_lakes gave. Assuming reasonable laziness of List.flatmap, this is both a clean and efficient solution.
As of 2017, the previous answers seem to be outdated. I ran some benchmarks (list of 10 million Ints, first match roughly in the middle, Scala 2.12.3, Java 1.8.0, 1.8 GHz Intel Core i5). Unless otherwise noted, list and map have the following types:
list: scala.collection.immutable.List
map: A => Option[B]
Simply call map on the list: ~1000 ms
list.map(map).find(_.isDefined).flatten
First call toStream on the list: ~1200 ms
list.toStream.map(map).find(_.isDefined).flatten
Call toStream.flatMap on the list: ~450 ms
list.toStream.flatMap(map(_).toList).headOption
Call flatMap on the list: ~100 ms
list.flatMap(map(_).toList).headOption
First call iterator on the list: ~35 ms
list.iterator.map(map).find(_.isDefined).flatten
Recursive function find(): ~25 ms
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
list match {
case Nil => None
case head::tail => map(head) match {
case None => find(tail, map)
case result # Some(_) => result
}
}
}
Iterative function find(): ~25 ms
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
for (elem <- list) {
val result = map(elem)
if (result.isDefined) return result
}
return None
}
You can further speed up things by using Java instead of Scala collections and a less functional style.
Loop over indices in java.util.ArrayList: ~15 ms
def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result.isDefined) return result
i += 1
}
return None
}
Loop over indices in java.util.ArrayList with function returning null instead of None: ~10 ms
def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result != null) return Some(result)
i += 1
}
return None
}
(Of course, one would usually declare the parameter type as java.util.List, not java.util.ArrayList. I chose the latter here because it's the class I used for the benchmarks. Other implementations of java.util.List will show different performance - most will be worse.)