I have a string that looks like this:
"7-6-4-1"
or
"7"
or
""
That is, a set of numbers separated by -. There may be zero or more numbers.
I want to return a stack with the numbers pushed on in that order (i.e. push 7 first and 1 ast, for the first example)
If I just wanted to return a list I could just go str.split("-").map{_.toInt} (although this doesn't work on the empty string)/
There's no toStack to convert to a Stack though. So currently, I have
{
val s = new Stack[Int];
if (x.nonEmpty)
x.split('-').foreach {
y => s.push(y.toInt)
}
s
}
Which works, but is pretty ugly. What am I missing?
EDIT: Thanks to all the responders, I learnt quite a bit from this discussion
Stack(x.split("-").map(_.toInt).reverse: _*)
The trick here is to pass the array you get from split into the Stack companion object builder. By default the items go in in the same order as the array, so you have to reverse the array first.
Note the "treat this is a list, not as a single item" annotation, : _*.
Edit: if you don't want to catch the empty string case separately, like so (use the bottom one for mutable stacks, the top for immutable):
if (x.isEmpty) Stack() else Stack(x.split("-").map(_.toInt).reverse: _*)
if (x.isEmpty) Stack[Int]() else Stack(x.split("-").map(_.toInt).reverse: _*)
then you can filter out empty strings:
Stack(x.split("-").filterNot(_.isEmpty).map(_.toInt).reverse: _*)
which will also "helpfully" handle things like 7-9----2-2-4 for you (it will give Stack(4,2,2,9,7)).
If you want to handle even more dastardly formatting errors, you can
val guard = scala.util.control.Exception.catching[Int](classOf[NumberFormatException])
Stack(x.split("-").flatMap(x => guard.opt(x.toInt)).reverse: _*)
to return only those items that actually can be parsed.
(Stack[Int]() /: (if(x.isEmpty) Array.empty else x.split("-")))(
(stack, value) =>
stack.push(value toInt))
Dont forget the ever handy breakOut which affords slightly better performance than col: _* (see Daniel's excellent explanation)
Used here with Rex Kerr's .filterNot(_.isEmpty) solution:
import scala.collection.immutable.Stack
import scala.collection.breakOut
object StackFromString {
def stackFromString(str: String): Stack[Int] =
str.split("-").filterNot(_.isEmpty)
.reverse.map(_.toInt)(breakOut)
def main(args: Array[String]): Unit = {
println(stackFromString("7-6-4-1"))
println(stackFromString("7"))
println(stackFromString(""))
}
}
Will output:
Stack(1, 4, 6, 7)
Stack(7)
Stack()
Related
I have a map with differnt keys and multiple values.If there is any matching job among different keys,I have to display only one row and grouping code values.
def data = ['Test1':[[name:'John',dob:'02/20/1970',job:'Testing',code:51],[name:'X',dob:'03/21/1974',job:'QA',code:52]],
'Test2':[name:'Michael',dob:'04/01/1973',job:'Testing',code:52]]
for (Map.Entry<String, List<String>> entry : data.entrySet()) {
String key = entry.getKey();
List<String> values = entry.getValue();
values.eachWithIndex{itr,index->
println("key is:"+key);
println("itr values are:"+itr);
}
}
Expected Result : [job:Testing,code:[51,52]]
First flatten all the relevant maps, so whe just have a flat list of all of them, then basically the same as the others suggested: group by the job and just keep the codes (via the spread operator)
def data = ['Test1':[[name:'John',dob:'02/20/1970',job:'Testing',code:51],[name:'X',dob:'03/21/1974',job:'QA',code:52]], 'Test2':[name:'Michael',dob:'04/01/1973',job:'Testing',code:52]]
assert data.values().flatten().groupBy{it.job}.collectEntries{ [it.key, it.value*.code] } == [Testing: [51, 52], QA: [52]]
Note: the question will be changed according to the comments from the other answers.
Above code will give you the jobs and and their codes.
As of now, it's not clear, what the new expected output should be.
You can use the groovy's collection methods.
First you need to extract the lists, since you dont need the key of the top level element
def jobs = data.values()
Then you can use the groupBy method to group by the key "job"
def groupedJobs = jobs.groupBy { it.job }
The above code will produce the following result with your example
[Testing:[[name:John, dob:02/20/1970, job:Testing, code:51], [name:Michael, dob:04/01/1973, job:Testing, code:52]]]
Now you can get only the codes as values and do appropriate changes to make key as job by the following collect function
def result = groupedJobs.collect {key, value ->
[job: key, code: value.code]
}
The following code (which uses your sample data set):
def data = ['Test1':[name:'John', dob:'02/20/1970', job:'Testing', code:51],
'Test2':[name:'Michael', dob:'04/01/1973', job:'Testing', code:52]]
def matchFor = 'Testing'
def result = [job: matchFor, code: data.findResults { _, m ->
m.job == matchFor ? m.code : null
}]
println result
results in:
~> groovy solution.groovy
[job:Testing, code:[51, 52]]
~>
when run. It uses the groovy Map.findResults method to collect the codes from the matching jobs.
Here is a request in the data process, AlertRDD is used to produce unique alerts count and not unique alerts count for one day.
So I write below method include both two of them,
implicit class RDDOps(val rdd: RDD[(String, String)]) {
def addDistinctRDD() = {
rdd.distinct().map{
case (elem1, elem2) =>
(elem1, elem2, "AlertUniqueUsers")
} ++ rdd.map{
case (elem1, elem2) =>
(elem1, elem2, "Alerts")
}
}
}
When I run AlertRDD.addDistinctRDD.save(//path), the program will never stop, but if run it as as AlertRDD.cache.addDistinctRDD.save(//path), it works well.
Could anybody know the reason?
Update
It looks like nobody can answer my question, probably my question is not well understood.
Why I add unique AlertRDD and non-unique AlertRDD together?
Because the follow-up process of two RDDs is the same, Something like below excerpt code:
.map((_, 1))
.reduceByKey(_ + _)
.map()
....
.save($path)
If my solution is not the good one, can anyone suggest a better solution?
I'm using junit in scala to compare string output from my scala code. Something like :
val expected = """<Destination id="0" type="EMAIL">
<Address>
me#test.com
</Address>
<TimeZone>
US/Eastern
</TimeZone>
<Message>
</Message>
</Destination>
"""
val actual = getTextToLog()
info(" actual = " + actual)
assert(expected == actual)
The issue is that for some strings, assertions like :
assert(expected == actual)
work and for some they strings they dont. Even when I copy actual (logged to Eclipse console) from Eclipse console and paste it into expected just to be sure , the assertion still fails.
What am I missing?
OK, since this turns out to be a whitespace issues, you should sanitise the two strings before comparing them. Look at the RichString methods like .lines, for example, which might let you create a line-ending or whitespace-agnostic comparison method.
Here is one naive way of doing this with implicit conversions:
import scala.language.implicitConversions
object WhiteSpace {
implicit def strToWhiteSpace(s: String) = new WhiteSpace(s)
}
class WhiteSpace(val s: String) {
def `~==` (other: String) = s.lines.toList == other.lines.toList
}
which allows
import WhiteSpace._
assert(expected ~== actual)
Or you could extend the appropriate jutils class to add an agnostic version of assertEquals.
Note that this comparison deconstructs both strings in the same way. This is much safer than sending one of them on a round-trip conversion.
Whitespace/crlf issues are so common that there's no point fighting it by trying to stop the mismatches; just do agnostic comparisons.
I have a list of dict with keys ['name','content','summary',...]. All the values are strings. But some values are None. I need to remove all the new lines in content, summary and some other keys. So, I do this:
...
...
for item in item_list:
name = item['name']
content = item['content']
if content is not None: content = content.replace('\n','')
summary = item['summary']
if summary is not None: summary = summary.replace('\n','')
...
...
...
...
I somewhat feel that the if x is not None: x = x.replace('\n','') idiom not so intelligent or clean. Is there a more "pythonic" or better way to do it?
Thanks.
The code feels unwieldy to you, but part of the reason is because you are repeating yourself. This is better:
def remove_newlines(text):
if text is not None:
return text.replace('\n', '')
for item in item_list:
name = item['name']
content = remove_newlines(item['content'])
summary = remove_newlines(item['summary'])
If you are going to use sentinel values (None) then you will be burdened with checking for them.
There are a lot of different answers to your question, but they seem to be missing this point: don't use sentinel values in a dictionary when the absence of an entry encodes the same information.
For example:
bibliography = [
{ 'name': 'bdhar', 'summary': 'questioner' },
{ 'name': 'msw', 'content': 'an answer' },
]
then you can
for article in bibliography:
for key in article:
...
and then your loop is nicely ignorant of what keys, if any, are contained in a given article.
In reading your comments, you claim that you are getting the dict from somewhere else. So clean it of junk values first. It is much more clear to have a cleaning step then it is to carry their misunderstanding through your code.
Python has a ternary operator, so one option is to do this in a more natural word order:
content = content.replace('\n', '') if content is not None else None
Note that if "" and None are equivalent in your case (which appears to be so), you can shorten it to just if content, as non-empty strings evaluate to True.
content = content.replace('\n', '') if content else None
This also follows the Python idiom of explicit is better than implicit. This shows someone following the code that the value can be None very clearly.
It's worth noting that if you repeat this operation a lot, it might be worth encapsulating it as a function.
Another idiom in Python is ask for forgiveness, not permission. So you could simply use try and except the AttributeError that follows, however, this becomes a lot more verbose in this case, so it's probably not worth it, especially as the cost of the check is so small.
try:
content = content.replace('\n', '')
except AttributeError:
content = None
#pass #Also an option, but as mentioned above, explicit is generally clearer than implicit.
One possibility is to use the empty string instead of None. This is not a fully general solution, but in many cases if your data is all of a single type, there will be a sensible "null" value other than None (empty string, empty list, zero, etc.). In this case it looks like you could use the empty string.
The empty string evaluates to False in Python, so the Pythonic way is if content:.
In [2]: bool("")
Out[2]: False
In [3]: bool("hello")
Out[3]: True
Side note but you can make your code a little clearer:
name, content = item["name"], item["content"]
And:
content = content.replace('\n','') if content else None
You might also consider abstracting some of your if clauses into a separate function:
def remove_newlines(mystr):
if mystr:
mystr = mystr.replace('\n')
return mystr
(edited to remove the over-complicated solution with dictionaries, etc)
Try:
if content: content = content.replace('\n','')
--
if content will (almost1) always be True as long as content contains anything except for 0, False, or None.
1As Lattyware correctly points out in the comments, this is not strictly True. There are other things that will evaluate to False in an if statement, for example, an empty list. See the link provided in the comment below.
I think that the "pythonic" thing is to use the fact that None will evaluate to False in an if statement.
So you can just say:
if content: content = content.replace('\n','')
I've got the following code on a Controller
def db = new Sql(dataSource)
def rawLines = db.rows("SELECT name FROM LINES")
def lines = []
/*(db.rows returns the values as [NAME:value] */
rawLines.each {
lines.add(it.name)
}
/*Then, use lines */
I can't keep away the impression that there is probably some way to do this in a more elegant way, something similar to a list comprehension in Python:
lines = [ l.name for l in db.rows("SELECT name FROM LINES") ]
Having to declare an empty list and then populate it doesn't seem the best way of doing things...
Is it possible to do something like this, or Groovy doesn't allow it?
Can't you just use the spread operator, and do:
lines = rawLines*.name
(see http://docs.groovy-lang.org/latest/html/documentation/index.html#_spread_operator)
tim_yates' answer is a clean solution when you want to call a method (or property) on each element of list in order to transform it e.g.:
[1,2,3]*.multiply(5)
but if you want to call a method from another object or do something more complex you can use collect:
[1, 2, 3].collect {Math.cos(it * Math.PI)}
Well, If you are using grails, why aren't you simply using the a model class together with the findAll method?
Using plain raw SQL should be done on exceptional cases.