Behaviour of Scala underscore not work like element of list - scala

Hi I am new in scala, and of course have a newbie question,
why the underscore character not work in this cases
my undertanding about underscore in this case it represent one element of the list
val listOftuple = List(("cat","tom"),("mouse","jerry"),("dog","spike"))
val listOfarray = List(Array("cat","tom"),Array("mouse","jerry"),Array("dog","spike"))
tuplelist.map(it=>it._1+it._2) //Ok
tuplelist.map(_._1+_._2) //Not work, give me: error: missing parameter type for expanded function
listOfarray.map(_.length) //Here work, like array.length
listOfarray.map(it=>it(0)+it(1)) //Ok
listOfarray.map(_=>_(0)+_(1))//Not work, give me: error: missing parameter type for expanded function
listOfarray.map(_(0)+_(1))//Not work, give me: error: missing parameter type for expanded function
may be i fall in a lexical misunderstanding ?
how to fix the error msg?
greetings

tuplelist.map(_._1+_._2)
Each time you use _, it stands for another parameter. That is, _ + _ is equivalent to (x,y) => x+y, not x => x+x. So the above is equivalent to tuplelist.map((x, y) => _._1 + _._2), which does not work because map expects a function that takes only one argument.
listOfarray.map(_=>_(0)+_(1))
Using _ as the name of a function parameter just means that the parameter will be ignored. When you use _ inside the function's body, it is still the function shortcut operator, not a reference to the ignored parameter. So the above lambda is equivalent to ignoredParam => (x, y) => x + y.
listOfarray.map(_(0)+_(1))
(x,y) => x(0) + y(1), but you want x => x(0) + x(1).
how to fix the error msg?
In all of these cases, using an explicit parameter list is the correct solution. You simply can't use the shortcut notation if you want to use the same parameter more than once.

Related

What does an underscore after a scala method call mean?

The scala documentation has a code example that includes the following line:
val numberFunc = numbers.foldLeft(List[Int]())_
What does the underscore after the method call mean?
It's a partially applied function. You only provide the first parameter to foldLeft (the initial value), but you don't provide the second one; you postpone it for later. In the docs you linked they do it in the next line, where they define squares:
val numberFunc = numbers.foldLeft(List[Int]())_
val squares = numberFunc((xs, x) => xs:+ x*x)
See that (xs, x) => xs:+ x*x, that's the missing second parameter which you omitted while defining numberFunc. If you had provided it right away, then numberFunc would not be a function - it would be the computed value.
So basically the whole thing can also be written as a one-liner in the curried form:
val squares = numbers.foldLeft(List[Int]())((xs, x) => xs:+ x*x)
However, if you want to be able to reuse foldLeft over and over again, having the same collection and initial value, but providing a different function every time, then it's very convinient to define a separate numbersFunc (as they did in the docs) and reuse it with different functions, e.g.:
val squares = numberFunc((xs, x) => xs:+ x*x)
val cubes = numberFunc((xs, x) => xs:+ x*x*x)
...
Note that the compiler error message is pretty straightforward in case you forget the underscore:
Error: missing argument list for method foldLeft in trait
LinearSeqOptimized Unapplied methods are only converted to functions
when a function type is expected. You can make this conversion
explicit by writing foldLeft _ or foldLeft(_)(_) instead of
foldLeft. val numberFunc = numbers.foldLeft(ListInt)
EDIT: Haha I just realized that they did the exact same thing with cubes in the documentation.
I don't know if it helps but I prefer this syntax
val numberFunc = numbers.foldLeft(List[Int]())(_)
then numberFunc is basically a delegate corresponding to an instance method (instance being numbers) waiting for a parameter. Which later comes to be a lambda expression in the scala documentation example

Spark Group By Key to (Key,List) Pair

I am trying to group some data by key where the value would be a list:
Sample data:
A 1
A 2
B 1
B 2
Expected result:
(A,(1,2))
(B,(1,2))
I am able to do this with the following code:
data.groupByKey().mapValues(List(_))
The problem is that when I then try to do a Map operation like the following:
groupedData.map((k,v) => (k,v(0)))
It tells me I have the wrong number of parameters.
If I try:
groupedData.map(s => (s(0),s(1)))
It tells me that "(Any,List(Iterable(Any)) does not take parameters"
No clue what I am doing wrong. Is my grouping wrong? What would be a better way to do this?
Scala answers only please. Thanks!!
You're almost there. Just replace List(_) with _.toList
data.groupByKey.mapValues(_.toList)
When you write an anonymous inline function of the form
ARGS => OPERATION
the entire part before the arrow (=>) is taken as the argument list. So, in the case of
(k, v) => ...
the interpreter takes that to mean a function that takes two arguments. In your case, however, you have a single argument which happens to be a tuple (here, a Tuple2, or a Pair - more fully, you appear to have a list of Pair[Any,List[Any]]). There are a couple of ways to get around this. First, you can use the sugared form of representing a pair, wrapped in an extra set of parentheses to show that this is the single expected argument for the function:
((x, y)) => ...
or, you can write the anonymous function in the form of a partial function that matches on tuples:
groupedData.map( case (k,v) => (k,v(0)) )
Finally, you can simply go with a single specified argument, as per your last attempt, but - realising it is a tuple - reference the specific field(s) within the tuple that you need:
groupedData.map(s => (s._2(0),s._2(1))) // The key is s._1, and the value list is s._2

why scala lambda with _ can't using && to combine two bool expression

As far as I understand .
_ is a short lambda to omit a=>
i find this code (can find here scala-function-true-power)
val file = List("warn 2013 msg", "warn 2012 msg", "error 2013 msg", "warn 2013 msg")
val size = file.filter(_.contains("warn")).filter(_.contains("2013")).size
//val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
val size2 = file.filter( a=> a.contains("warn") && a.contains("2013")).size
println("cat file | grep 'warn' | grep '2013' | wc : " +size )
the line to get size1 has syntax error,looks like it can't recognize the "_" ,it's not a element in fileList.
but i use a=>,the normal kind,it works good .
so,why the scala work by this way?
is there more difference in _ and a=> ?
In scala, any _ placeholder is matched against the passed arguments in the context of calling function. So for example if the signature of the function you are trying to use is f : A ⇒ B and you are calling something like collectionOfFunctA.map(_.f) - Scala compiler will infer the correct type of the function and will use the first underscore to put the actual item from a collection and call the function f over it. But if you will try to write it as collectionOfFunctA.map(_.f + _.size) - that will fail, because Scala compiler will pick up the first placeholder as of type that has function f defined, and the second underscore will not match any function in the context. So it will expect to have a function that takes two parameters instead of one.
More on this
As jdevelop says, but here in the words of the compiler/REPL:
scala> val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
^
You see that hint: for expanded function ((x$1, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
It is expecting 2 parameters while there is just one.
You can think of the place holder as being matched with the lambda's arguments positionnally.
The first occurrence of the _ is matched with the first argument, the second occurence is matched with the second argument, etc.
As the other answers have shown, this means that using the placeholder twice will be desugared as trying to pass a lamba with 2 arguments to the filter which only expects one.
In your example :
val size = file.filter(_.contains("warn") && _.contains("2013")).size
would be desugared as
val size = file.filter((a,b)=>a.contains("warn") && b.contains("2013")).size
which will not compile since filter expects a predicate p: A => Boolean
Now, a reason the placeholder is matched positionnally is to avoid ambiguity in lambdas with more than one argument.
How can the compiler guess the correct implementation for the following case if the place holder can be reused multiple times for the same argument:
file.fold("")(_++_)
Should it be desugared as :
file.fold("")((a,b)=> a++b )
or as
file.fold("")((a,b)=> a++a )
or as
file.fold("")((a,b)=> b++b )
and worse, what would you expect for
file.fold("")(_++_++_)
There is no general way for the compiler to infer the correct implementation.
One might argue for relaxing the constraint when the expected lambda only accepts one argument. I suggest doing a more detailed research before taking the first steps to the scala improvement process as it seems likely that this particular design decision has been challenged and explained before.
If you are worried about the performance of iterating over the list twice (which is the case when you write)
file.filter(_.contains("warn")).filter(_.contains("2013")).size
In theory it should be possible for the compiler to detect that both filters can be applied within the same iteration.
In scala, the collections are eager by default but you can get the lazy evaluation by using views.
The current implementation has known issues which are being worked on. Other collection implementations in scala are actively being developed to be able to combine transformations and computations by default (see psp-std for example)

Usage of _ in scala lambda functions

Can anyone please explain me why I can do:
a.mapValues(_.size)
instead of
a.mapValues(x => x.size)
but I can't do
a.groupBy(_)
instead of a
a.groupBy(x => x)
When you write a.groupBy(_) the compiler understands it as an anonymous function:
x => a.groupBy(x)
According to Scala Specifications §6.23, an underscore placeholder in an expression is replaced by a anonymous parameter. So:
_ + 1 is expanded to x => x + 1
f(_) is expanded to x => f(x)
_ is not expanded by itself (the placeholder is not part of any expression).
The expression x => a.groupBy(x) will confuse the compiler because it cannot infer the type of x. If a is some collection of type E elements, then the compiler expects x to be a function of type (E) => K, but type K cannot be inferred...
It isn't easy to see it here:
a.groupBy(_)
But it's easier to see it in something like this:
a.mkString("<", _, ">")
I'm partially applying the method/function. I'm applying it to some parameters (the first and last), and leaving the second parameter unapplied, so I'm getting a new function like this:
x => a.mkString("<", x, ">")
The first example is just a special case where the sole parameter is partially applied. When you use underscore on an expression, however, it stands for positional parameters in an anonymous function.
a.mapValues(_.size)
a.mapValues(x => x.size)
It is easy to get confused, because they both result in an anonymous function. In fact, there's a third underscore that is used to convert a method into a method value (which is also an anonymous function), such as:
a.groupBy _

Scala underscore minimal function

Let's create a value for the sake of this question:
val a = 1 :: Nil
now, I can demonstrate that the anonymous functions can be written in shorthand form like this:
a.map(_*2)
is it possible to write a shorthand of this function?:
a.map((x) => x)
my solution doesn't work:
a.map(_)
For the record, a.map(_) does not work because it stands for x => a.map(x), and not a.map(x => x). This happens because a single _ in place of a parameter stands for a partially applied function. In the case of 2*_, that stands for an anonymous function. These two uses are so close that is very common to get confused by them.
Your first shorthand form can also be written point-free
a map (2*)
Thanks to multiplication being commutative.
As for (x) => x, you want the identity function. This is defined in Predef and is generic, so you can be sure that it's type-safe.
You should use identity function for this use case.
a.map(identity)
identity is defined in scala.Predef as:
implicit def identity[A](x: A): A = x