I have a list of two-item lists:
def list = [[key1, value1], [key1, value1], [key2, value1], [key2, value2], ...]
I am trying to write Groovy code which will take "list" and return another list, which displays not only the frequency of each duplicate, two-item list, but also if there are items which are unique:
def newList = [[key1, value1:2], [key2, [value1:1, value2:1]], ...];
The reasoning behind this format is because I'd write more code to throw an error if a specific "key" had more than one "value". If there is an easier way to do this, any help/suggestions would be appreciated.
It normally helps if you show what you've tried when asking a question here...
In this case though, you just need:
def result = list.groupBy { it[0] }
.collect { k, v -> [k, v.countBy { it[1] }] }
And result will equal:
[['key1', ['value1':2]], ['key2', ['value1':1, 'value2':1]]]
You could also do something like this:
def result = list.groupBy { it[0] }
.collectEntries { k, v -> [k, v*.getAt(1).unique().size() ] }
To give you:
['key1':1, 'key2':2]
Related
def find(list: List[(Char,Int)]): List[(Char,Int)] = {
list match {
case List() => List()
case (z,y):: xs => ((for(i <- 1 to y) yield (z,i)).toList ::: find(xs).toList)
}
find(List(('a',5),('b',3))) // will return nothing at all
I simply cannot understand why such a function will return empty for the given arguments. It does not have arguments which are empty so what could be the problem here?
This might be a very easy question but I really need a fresh pair of eyes to help me debug this as I simply am not able to spot the silly mistake I made
Your function appears to work properly for me as it returns this:
List((a,1), (a,2), (a,3), (a,4), (a,5), (b,1), (b,2), (b,3))
I did notice in the code you provided you're missing a closing bracket on your find function, it should look like this:
def find(list: List[(Char, Int)]): List[(Char, Int)] = {
list match {
case List() => List()
case (z, y) :: xs => (for (i <- 1 to y) yield (z, i)).toList ::: find(xs)
}
}
I'm trying to write the get method for a key, value pair implemented using a list. I want to use the Option type as I heard its good for this but I'm new to Scala and I'm not really sure how to use it in this case...
This is as far as I got, only the method header.
def get(key : String): Option[Any] = {}
My guess is you are looking for something like this:
class KeyValueStore(pairs: List[(String, Any)]) {
def get(key: String): Option[Any] = pairs.collectFirst {
case (k, v) if k == key => v
}
}
This uses the collectFirst method for sequences. If you want a more "do it yourself" approach, this should work:
def get(key: String): Option[Any] = {
def search(xs: List[(String, Any)]): Option[Any] = {
xs match {
case List() => None //end of list and key not found. We return None
case (k, v) :: rest if k == key => Some(v) // found our key. Returning some value
case _ :: rest => search(rest) // not found until nou. Carrying on with the rest of the list
}
search(pairs)
}
}
You can turn a List of Pairs into a Map:
class Store[K, V](values: List[(K, V)]) {
val map = values.toMap
def get(key: K): Option[V] = map get key
}
Although #Marius' collectFirst version is probably the most elegant (and maybe a little bit faster as it only uses one closure), I find it more intuitive to use find for your problem :
def get[A, B](key: A, pairs: List[(A, B)]): Option[B] = pairs.find(_._1 == key).map(_._2)
In case you were wondering (or need high performance), you will need either #Marius' recursive or the following imperative version which may look more familiar (although less idiomatic):
def get[A, B](key: A, pairs: List[(A, B)]): Option[B] = {
var l = pairs
var found: Option[B] = None
while (l.nonEmpty && found.isEmpty) {
val (k, v) = l.head
if (k == key) {
found = Some(v)
} else {
l = l.tail
}
}
found
}
What you must understand is that Option[B] is a class that may either be instantiated to None (which replaces and improves the null reference used in other languages) or Some(value: B). Some is a case class, which allows, among other neat features, to instantiate it without the new keyword (thanks to some compiler magic, Google Scala case class for more info). You can think of Option as a List which may contain either 0 or 1 element: most operations that can be done on sequences can also be applied to Options (such as map in the find version).
I have the following code:
type foo= List[bar]
def emtfoo= List[bar]()
def permute(s1:Set[foo],s2:Set[foo]):Set[foo]={
for{
x<-s1
y<-s2
}yield permutatefoo(x,y,e,emtfoo)
def permutatefoo(l1:foo,l2:foo,sofar:foo):Set[foo]={
if (l1.equals (emtfoo)) {
Set{sofar:+l2}
}
else {
combine(permutatefoo(l1.drop(1),l2,l1.take(1):::sofar),
permutatefoo(l1,l2.drop(1),l2.take(1):::sofar))
}
}
def combine(s1:Set[foo],s2:Set[foo]):Set[foo] =
for {
x <- s1
y<- s2
} yield x ::: y
Which should be fairly straightforward code to permutate 2 sets of lists into a single set which has all possible permutations of both lists in order with no element appearing in front of an element in wasn't in front of in the list itself (so if we have list a = 1,2,3 and list b =a,b,c then it should return the Set{1,a,2,b,3,c-1,2,a,3,b,c-a,1,2,3,b,c ext.}).
However my code generates a few errors type mistmaches around the line.
{Set{sofar:+l2}}
and
x<-s1
Does anybody know how to fix this?
I'm not sure I grok all your code, but a few things I see are:
1:
{Set{sofar:+l2}} // should probably be Set(sofar ++ l2)
// as it seems you just want to concatenate sofar and l2
// which are both List[bar] (so your return value is a Set[foo]
// i.e. a Set[List[bar]] as the signature for
// permutatefoo requests
:+ is an extractor (see the doc) and it's not supposed to be used in that way
2:
if (l1.equals (emtfoo)) // you should also check against ls.equals(emtfoo)
// as you're also dropping elements from l2
// in permutatefoo(l1,l2.drop(1),l2.take(1):::sofar))
3:
the return type for permute is wrong. The way you defined it, it returns a Set[Set[foo]] instead of a Set[foo]. I'm not sure I understand what you want it to do, but if you fix the return type it should at least type-check.
This is a version of your code that compiles. I'm not saying it works (as I said, I'm not sure I understand what all the expected inputs and outputs for your program should be), but it compiles.
type bar=Int
type foo= List[bar]
def emtfoo= List[bar]()
def combine(s1:Set[foo],s2:Set[foo]) =
for{
x <- s1
y <- s2
} yield x ++ y
def permutatefoo(l1:foo, l2:foo, sofar:foo): Set[foo]={
if (l1.equals (emtfoo) || l2.equals (emtfoo)) {
Set(sofar ++ l2)
}
else
{
combine(permutatefoo(l1.drop(1),l2,l1.take(1) ++ sofar),
permutatefoo(l1,l2.drop(1),l2.take(1) ++ sofar))
}
}
def permute(s1:Set[foo],s2:Set[foo]) : Set[Set[foo]] = {
for {
x <- s1
y <- s2
} yield permutatefoo(x,y,emtfoo)
}
I have often the need to check if many values are equal and in case extract the common value. That is, I need a function that will work like follows:
extract(List()) // None
extract(List(1,2,3)) // None
extract(List(2,2,2)) // Some(2)
Assuming one has a pimp that will add tailOption to seqs (it is trivial to write one or there is one in scalaz), one implementation looks like
def extract[A](l: Seq[A]): Option[A] = {
def combine(s: A)(r: Seq[A]): Option[A] =
r.foldLeft(Some(s): Option[A]) { (acc, n) => acc flatMap { v =>
if (v == n) Some(v) else None
} }
for {
h <- l.headOption
t <- l.tailOption
res <- combine(h)(t)
} yield res
}
Is there something like that - possibly more general - already in Scalaz, or some simpler way to write it?
This seems like a really complicated way to write
def extract[A](l:Seq[A]):Option[A] = l.headOption.flatMap(h =>
if (l.tail.forall(h==)) Some(h) else None)
You don't need tailOption, since the anonymous function that gets passed as an argument to flatMap is only executed if l is not empty.
If you only want to delete duplicates toSet is enough:
def equalValue[A](xs: Seq[A]): Option[A] = {
val set = xs.toSet
if (set.size == 1) Some(set.head) else None
}
scala> equalValue(List())
res8: Option[Nothing] = None
scala> equalValue(List(1,2,3))
res9: Option[Int] = None
scala> equalValue(List(2,2,2))
res10: Option[Int] = Some(2)
This is a fluent solution
yourSeq.groupBy(x => x) match {case m if m.size==1 => m.head._1; case _ => None}
You could use a map to count the number of occurrences of each element in the list and then return only those that occur more than once:
def extract[T](ts: Iterable[T]): Iterable[T] = {
var counter: Map[T, Int] = Map()
ts.foreach{t =>
val cnt = counter.get(t).getOrElse(0) + 1
counter = counter.updated(t, cnt)
}
counter.filter(_._2 > 1).map(_._1)
}
println(extract(List())) // List()
println(extract(List(1,2,3))) // List()
println(extract(List(2,2,2))) // List(2)
println(extract(List(2,3,2,0,2,3))) // List(2,3)
You can also use a foldLeft instead of foreach and use the empty map as the initial accumulator of foldLeft.
I have a query result of List[ Tuple3[User, Order, OrderItem] ]
To create a case class instance of an Invoice, its companion object takes a User, Order and a List[OrderItem].
Currently I'm hacking it out something like:
def getInvoice(orderNum: String): Option[Invoice] = {
val res =
dao.byOrderNum(orderNum) // List[ Tuple3[User, OrderEntry, OrderItem] ]
if(!res.isEmpty) {
val(user, order) = (res(0)._1, res(0)._2)
val items = res map { case(_, _, oi: OrderItem) => oi }
Some( Invoices.apply(user, order, items) ) // gets an Invoice
}
else None
}
I could make the query result a List[ Option[Tuple3[User, Order, OrderItem]] ], which would let me flatMap over the result, but not sure what that buys me.
At any rate, must be a more concise/elegant solution to the problem
Thanks
The following should be exactly equivalent:
def getInvoice(orderNum: String): Option[Invoice] = {
val res = dao.byOrderNum(orderNum)
res.headOption.map {
case (user, order, _) => Invoices(user, order, res.map(_._3))
}
}
The key is headOption, which handles the checking for emptiness in a more idiomatic way (it gives None for an empty sequence and Some(xs.head) for a non-empty one).
The headOption thing is neat and you might as well use it since it's there, but you could simply pattern match on the List (rather than mapping an Option), which is kind of what you in the question, but it just needs a bit of tidying up:
res match {
case (a, b, _) :: _ => Some(Invoices(a, b, res.map(_._3)))
case _ => None
}