I have the following Scala code in my program:
val parser = new PlainToTokenParser(...)
for {
word: Word <- parser.next()
if word == null
} {
print(word)
}
where PlainToTokenParser is a java class in another library:
public class PlainToTokenParser implements Parser {
public PlainToTokenParser(Parser p) {
this.parser = p;
}
public Object next() {
// some work here and return an output
}
}
when compiling my scala code I get the following error:
... value filter is not a member of Object
[error] for{ word: Word <- parser.next()
[error]
Any idea where I am going wrong?
Because PlainToTokenParser is not a scala iterator, you must create a scala iterator to use for loop.
val parser = new PlainToTokenParser(...)
for {
word <- Iterator.continually(parser.next).takeWhile(_ != null) // Assume null is the end
} {
print(word)
}
BTW: you can loop through java Array/Map because scala implicit create an iterator.
The for-loop iterates over an object. You want to iterate over the Words returned by parser. But your code actually takes the first Word and tries to iterate over that. (Also a problem is that next returns an Object while your variable is of type Word.)
Scala compiles a for-loop into a series of method calls. The spec says it will translate into map, withFilter, flatMap, and foreach. The object you want to iterate over must have (at least some of) these methods for the for-loop to work. Looks like for some reason it's actually trying to call filter on the Object returned by parser.next().
(See Zeng's answer for a solution. I thought an explanation would be useful too.)
Related
I am writting a scala function which follows the following workflow:
take an id as parameter.
use the id to get a object from mongo database. Here I am using reactive mongo.
after getting the object make another query to the database to get a list of items and return it.
I have implemented this workflow in the following way:
def functionA(id:String):Future[List[Hotel]]={
var futureHotel = hotelRepository.getHotel(id) // returns Futue[Option[Hotel]]
val result = for {
r<-futureHotel
}yield (hotelRepository.getHotels(r.get.giataid)) // this is supposed to be Future[List[Hotel]]
}
It gives me error message like: Type mismatch. Found Unit require Future[List[Hotel]]
As I am new to Scala, I am sure I am missing something. Will be cool if someone can point out. Any clue or help will be appreciated.
You are assigning the result to result. Assignment in scala is of type Unit (doesn't return anything). Remove the assignment, since the last expression becomes the return value.
Also, if the getHotels method returns Future[List[...]] you'll end up with Future[Future[List[...]]. You probably want something like this:
def functionA(id:String):Future[List[Hotel]]= {
for {
r <- hotelRepository.getHotel(id)
result <- hotelRepository.getHotels(r.get.giataid)
} yield result
}
This gets translated to a call to flatMap that doesn't produce the doubly nested future.
I am new to scala mongodb my code is
while(result.hasNext)
{
if(result.next().containsField("profilepic"))
bl+=result.next().get("profilepic").toString()
}
It works for next but what about curr().I Doesn't found any method
I want something like this
bl+=result.curr().get("profilepic").toString()
But in scala their is no method such as curr() any alternative?
Disclaimer: I'm fairly new to Scala, but have much more extensive Java experience.
I guess the problem with your code is that you call next() twice while in each iteration of the loop (so you're acting on two elements), while your intent is clearly to act on one. This code will probably work for you:
while(result.hasNext) {
val curr = result.next
if(curr.containsField("profilepic")) {
bl += curr.get("profilepic").toString()
}
}
Read the following section about Iterator semantics: http://www.scala-lang.org/docu/files/collections-api/collections_43.html
The important thing to understand is that each next called on an Iterator will yield a new element:
val result = Iterator("foo", "bar", "baz")
result.next == "foo" // true
result.next == "bar" // true
In your case you want to act on the same element several times. Store it in a variable (e.g. curr) and make sure you call next exactly once during each iteration.
Why does queue.get() return empty list?
class MyQueue{
var queue=List[Int](3,5,7)
def get(){
this.queue.head
}
}
object QueueOperator {
def main(args: Array[String]) {
val queue=new MyQueue
println(queue.get())
}
}
How i can get first element?
It's not returning the empty list, it's returning Unit (a zero-tuple), which is Scala's equivalent of void in Java. If it were returning the empty list you'd see List() printed to the console rather than the () (nullary tuple).
The problem is you're using the wrong syntax for your get method. You need to use an = to indicate that get returns a value:
def get() = {
this.queue.head
}
Or this is probably even better:
def get = this.queue.head
In Scala you usually leave off the parentheses (parameter list) for nullary functions that have no side-effects, but this requires you to leave the parentheses off when you call queue.get as well.
You might want to take a quick look over the Scala Style Guide, specifically the section on methods.
Sometimes it can be good to use
take 1
instead of head because it doesnt cause an exception on empty lists and returns again an empty list.
I'm really new to Scala and I'm not even able to concatenate Strings. Here is my code:
object RandomData {
private[this] val bag = new scala.util.Random
def apply(sensorId: String, stamp: Long, size: Int): String = {
var cpt: Int = 0
var data: String = "test"
repeat(10) {
data += "_test"
}
return data
}
}
I got the error:
type mismatch;
found : Unit
required: com.excilys.ebi.gatling.core.structure.ChainBuilder
What am I doing wrong ??
repeat is offered by Gatling in order to repeat Gatling tasks, e.g., query a website. If you have a look at the documentation (I wasn't able to find a link to the API doc of repeat), you'll see that repeat expects a chain, which is why your error message says "required: com.excilys.ebi.gatling.core.structure.ChainBuilder". However, all you do is to append to a string - which will not return a value of type ChainBuilder.
Moreover, appending to a string is nothing that should be done via Gatling. It looks to me as if you are confusing Gatling's repeat with a Scala for loop. If you only want to append "_test" to data 10 times, use one of Scala's loops (for, while) or a functional approach with e.g. foldLeft. Here are two examples:
/* Imperative style loop */
for(i <- 1 to 10) {
data += "_test"
}
/* Functional style with lazy streams */
data += Stream.continually("_test").take(10).mkString("")
Your problem is that the block
{
data += "_test"
}
evaluates to Unit, whereas the repeat method seems to want it to evaluate to a ChainBuilder.
Check out the documentation for the repeat method. I was unable to find it, but it's probably reasonable to assume that it looks something like
def repeat(numTimes: Int)(thunk: => ChainBuilder): Unit
I'm not sure if the repeat method does anything special, but with your usage, you could just use this block instead of the repeat(10){...}
for(i <- 1 to 10) data += "_test"
Also, as a side note, you don't need the return keyword with scala. You can just say data instead of return data.
I have to translate the following code from Java to Scala:
EDIT: added if-statements in the source (forgot them in first version)
for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();)
{
if (someCondition) {
ExceptionQueuedEvent event = i.next();
try {
//do something
} finally {
i.remove();
}
}
}
I'm using the JavaConversions library to wrap the Iterable. But as i'm not using the original Iterator, i don't know how to remove the current element correctly from the collection the same way as i did in Java:
import scala.collection.JavaConversions._
(...)
for (val event <- events) {
if (someCondition) {
try {
// do something
} finally {
// how can i remove the current event from events?
// the underlying type of events is java.lang.Iterable[javax.faces.event.ExceptionQueuedEvent]
}
}
}
Can someone help me?
I guess it's easy, but i'm still kinda new to Scala and don't understand what's going on when Scala wraps something of Java.
When you use JavaConversions to wrap Java collections, you just get an object that adapts the Java collection to the appropriate Scala trait (interface). In Java, you might see the same thing (for example, you could imagine a adapter class that implements the Iterator interface and wraps an Enumeration.) The only difference is that in Scala you can add the 'implicit' modifier to a declaration to tell the compiler to automatically insert calls to that method if it will make the code compile.
As for your specific use case, Iterators in Scala intentionally omit the remove() method for a number of reasons. The conversion from scala.collection.Iterator to java.util.Iterator promises to unwrap a j.u.Iterator if possible, so I suppose you could rely on that to access the remove() method. However, if you are iterating over the entire collection and removing everything, why not just do your work in a foreach loop and then clear the collection or replace it with an empty one after you finish?
Does this suggest how do accomplish what you want?
scala> val l1 = List("How", "do", "I", "love", "you")
l1: List[java.lang.String] = List(How, do, I, love, you)
scala> val evens = for ( w <- l1; if w.length % 2 == 0 ) yield { printf("even: %s%n", w); w }
even: do
even: love
evens: List[java.lang.String] = List(do, love)
Basically, you get your Scala Iterable or Iterator using the appropriate implicit conversion from JavaConversions, use a for comprehension that includes the condition on which elements you want to process and collect the results. Use exception handling as necessary.
Thanks for all the help. So i had to do without using JavaConversions. But it still looks nice&scalafied ;)**
This is my final code, which seems to work:
val eventsIterator = events.iterator
for (eventsIterator.hasNext) {
if (someCondition) {
try {
// do something
} finally {
eventsIterator.remove
}
}
}