I must handle with sequences of orders (here Int for simplification):
// the handleOrder methods are in fact much more complicated:
def handleOrders(prev: Double, orders: Seq[Int]): Double = prev + orders.sum
def handleOrder(prev: Double, order: Int): Double = prev / order
As a result from a so called
def nextGroup(prev: Double, orders: Seq[Int]): Seq[Double]
function I get a sequence of another class (here Double for simplification).
From this I've implemented two versions.
Version 1 (foldLeft and explicit builder):
def nextGroup1(prev: Double, orders: Seq[Int]): Seq[Double] = {
import collection.mutable.Builder
import collection.immutable.VectorBuilder
val bld: Builder[Double, Seq[Double]] = new VectorBuilder[Double]
var first = true
orders.foldLeft(prev) { (prev, order) =>
val step = if (first) handleOrders(prev, orders) else prev
val next = handleOrder(step, order)
first = false
bld += next
next
}
bld.result
}
Version 2 (var and for yield builder):
def nextGroup2(prev: Double, orders: Seq[Int]): Seq[Double] = {
var first = true
var präv = prev
for (order <- orders) yield {
if (first) präv = handleOrders(präv, orders)
präv = handleOrder(präv, order)
first = false
präv
}
}
I'd like to save either explicit builder in version 1 or mutable var in version 2.
Is this possible? Perhaps with a combination of foldLeft and for-yield?
And still something sample data:
val orders = Seq(1, 2, 3)
nextGroup1(1d, orders) // => Vector(7.0, 3.5, 1.1666666666666667)
nextGroup2(1d, orders) // => List(7.0, 3.5, 1.1666666666666667)
nextGroup1(2d, orders) // => Vector(8.0, 4.0, 1.3333333333333333)
nextGroup2(2d, orders) // => List(8.0, 4.0, 1.3333333333333333)
The nextGroup results handled as Seq[Double], so Vector or List is no difference.
orders.tail.scanLeft(handleOrders(prev, orders)) { (p, o) => handleOrder(p, o) }
scanLeft does the same as foldLeft does but keeps all intermediate results. You can get rid of the special case by excluding the head of the collection which you can do using orders.tail.
Related
I'd like to know the idiomatic way to approach this problem in scala.
Given a start date and an end date and a collection of dates in between, determine whether the given collection of dates contains all the dates necessary to go from the start date to the end date with no gap dates in between.
Type signature:
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean
The "normal" or "not functional" way to do this would be something like this:
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean = {
i = 1
status = true
while(start != end) {
d = start.plusDays(i)
if (!between.contains(d) {
status = false
break
}
i += 1
}
return status
}
How can I do this using a Fold?
Here's my thought process so far:
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean = {
// A fold will assume the dates are in order and move left (or right)
// This means the dates must be sorted.
val sorted = between.sortBy(_.getMillis())
val a = sorted.foldLeft(List[Boolean]) {
(acc, current) => {
// How do I access an iterable version of the start date?
if (current == ??) {
acc :: true
} else false
}
}
// If the foldLeft produced any values that could NOT be matched
// to the between list, then the start date does not have an
// uninterrupted path to the end date.
if (a.count(_ == false) > 0) false
else true
}
I just need to figure out how to index the start parameter so I can increase the value of it as the fold iterates over the between collection. Or it's possible that fold isn't what I'm supposed to use at all.
Any help would be appreciated!
You can pass previous DateTime item in accumulator:
val a = sortedBetween.foldLeft((List[Boolean](), start)) {
case ((results, prev), current) => {
... calculate res here ...
(results ++ List(res), current)
}
}
But for this kind of check you better use sliding and forall combination:
sortedBetween.sliding(2).forall {
case List(prev,cur) => ..do the check here ..
}
Also, note that you ingnoring the result of between sorting since IndexedSeq is immutable. Fix - use another val:
val sortedBetween = between.sortBy(_.getMillis())
I think a fold isn't necessary, it's making things too hard.
Suppose you had the following functions:
private def normalizeDateTime( dt : DateTime ) : DateMidnight = ???
private def requiredBetweens( start : DateMidnight, end : DateMidnight ) : Seq[DateMidnight] = ???
Then you could write your function as follows:
def checkDate(start: DateTime, end: DateTime, between: IndexedSeq[DateTime]): Boolean = {
val startDay = normalizeDateTime( start )
val endDay = normalizeDateTime( end )
val available = between.map( normalizeDateTime ).toSet
val required = requiredBetweens( startDay, endDay ).toSet
val unavailable = (required -- available)
unavailable.isEmpty
}
Note that this function imposes no requirement as to the ordering of the betweens, treats the elements as a Set, only requiring that each day be available somewhere.
To implement normalizeDateTime(...) you might get away with something as simple as dt.toDateMidnight, but you should think a bit about Chronology and time zone issues. It's critical that DateTime objects that you mean to represent a day always normalize to the same DateMidnight.
To implement requiredBetweens(...), you might consider using a Stream and takeWhile(...) for an elegant solution. You might want to require that (end isAfter start).
I would use filter and then zip and take the difference, the dates should always be one day apart, so check they are all 1.
# val ls = Array(1, 2, 3, 4, 5, 6, 7) // can use dates in the same way
ls: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7)
# val ls2 = ls.filter { i => (2 < i) && (i < 6) }
ls2: Array[Int] = Array(3, 4, 5)
# ls2.zip(ls2.drop(1))
res21: Array[(Int, Int)] = Array((3, 4), (4, 5))
# ls2.zip(ls2.drop(1)).map { case (x, y) => y-x }
res22: Array[Int] = Array(1, 1)
# ls2.zip(ls2.drop(1)).map { case (x, y) => y-x }.forall { _ == 1 }
res23: Boolean = true
You also have to check that no dates are missing:
# ls2.length == 6 - 2 - 1 // beware off-by-one errors
res25: Boolean = true
You may also be able to do this more simply by using the Range object:
# ls2.zipAll(3 to 5 by 1, 0, 0).forall { case (x, y) => x == y }
res46: Boolean = true
This should work, but may need a slight tweak for DateTime...
# val today = LocalDate.now
today: LocalDate = 2017-10-19
# val a = (0 to 9).reverse.map { today.minusDays(_) }
a: collection.immutable.IndexedSeq[LocalDate] = Vector(2017-10-10, 2017-10-11, 2017-10-12, 2017-10-13, 2017-10-14, 2017-10-15, 2017-10-16, 2017-10-17, 2017-10-18, 2017-10-19)
# a.zip(a.drop(1)).map { case (x, y) => x.until(y) }.forall { _ == Period.ofDays(1) }
res71: Boolean = true
Solution with tail recursion. I'm using ZonedDateTime from Java 8 for DateTime representation. Here is online version on codepad.remoteinterview.io:
import scala.annotation.tailrec
import java.time.ZonedDateTime
object TailRecursionExample {
def checkDate(start: ZonedDateTime, end: ZonedDateTime,
between: Seq[ZonedDateTime]): Boolean = {
// We have dates in range (inclusive) [start, end] with step = 1 day
// All these days should be in between collection
// set for fast lookup
val set = between.toSet
#tailrec
def checkDate(curr: ZonedDateTime, iterations: Int): (Int, Boolean) = {
if (curr.isAfter(end)) (iterations, true)
else if (set.contains(curr)) checkDate(curr.plusDays(1), iterations + 1)
else (iterations, false)
}
val (iterations, result) = if (start.isAfter(end))
(0, false)
else
checkDate(start, 0)
println(s"\tNum of iterations: $iterations")
result
}
def main(args: Array[String]): Unit = {
testWhenStartIsAfterEnd()
println
testWhenStartIsBeforeEnd()
println
testWhenStartIsBeforeEndButBetweenSkipOneDay()
println
()
}
def testWhenStartIsAfterEnd(): Unit = {
val start = ZonedDateTime.now().plusDays(5)
val end = ZonedDateTime.now()
val between = (0 to 5).map(i => start.plusDays(i))
verboseTest("testWhenStartIsAfterEnd", start, end, between)
}
def testWhenStartIsBeforeEnd(): Unit = {
val start = ZonedDateTime.now().minusDays(5)
val end = ZonedDateTime.now()
val between = (0 to 5).map(i => start.plusDays(i))
verboseTest("testWhenStartIsBeforeEnd", start, end, between)
}
def testWhenStartIsBeforeEndButBetweenSkipOneDay(): Unit = {
val start = ZonedDateTime.now().minusDays(5)
val end = ZonedDateTime.now()
val between = (1 to 5).map(i => start.plusDays(i))
verboseTest("testWhenStartIsBeforeEndButBetweenSkipOneDay", start, end, between)
}
def verboseTest(name: String, start: ZonedDateTime, end: ZonedDateTime,
between: Seq[ZonedDateTime]): Unit = {
println(s"$name:")
println(s"\tStart: $start")
println(s"\tEnd: $end")
println(s"\tBetween: ")
between.foreach(t => println(s"\t\t$t"))
println(s"\tcheckDate: ${checkDate(start, end, between)}")
}
}
I am having following 2 lists in scala.
case class Parents(name: String, savings: Double)
case class Children(parentName: String, debt: Double)
val parentList:List[Parents] = List(Parents("Halls",1007D), Parents("Atticus",8000D), Parents("Aurilius",900D))
val childrenList:List[Children] = List(Children("Halls",9379.40D), Children("Atticus",9.48D), Children("Aurilius",1100.75D))
val sortedParentList:List[Parents] = parentList.sortBy(_.savings).reverse
// sortedParentList = List(Parents(Atticus,8000.0), Parents(Halls,1007.0), Parents(Aurilius,900.0))
now my parenList is Sorted By savings in decreasing order, I want my childrenList to be sorted in the way that it follows parentList Order.
i.e. expected order will be following
// sortedParentList = List(Children(Atticus,9.48D), Children(Halls,9379.40D), Children(Aurilius,1100.75D))
Well, if you know both lists are initially in the same order (you can always ensure that by sorting both by name), you can just sort them both in one go:
val (sortedParentList, sortedChildrenList) = (parents zip children)
.sortBy(-_._1.savings)
.unzip
Or you can define the ordering ahead of time, and use it to sort both lists:
val order = parentList.map(p => p.name -> -p.savings).toMap
val sortedParentList = parentList.sortBy(order(_.name))
val sortedChildrenList = childrenList.sortBy(order(_.parentName))
Or you can sort parents first (maybe, they are already sorted), and then define the order:
val order = sortedParentList.zipWithIndex.map { case(p, idx) => p.name -> idx }.toMap
val sortedChildrenList = childrenList.sortBy(c => order(c.parentName))
case class Parents(name: String, savings: Double)
case class Children(parentName: String, debt: Double)
val familiesList: List[(Parents, Children)] = List(
Parents("Halls",1007D) -> Children("Halls",9379.40D),
Parents("Atticus",8000D) -> Children("Atticus",9.48D),
Parents("Aurilius",900D) -> Children("Aurilius",1100.75D))
val (sortedParents, sortedChildren) = familiesList.sortBy {
case (parents, _) => -parents.savings
}.unzip
The example below is a self-contained example I've extracted from my larger app.
Is there a better way to get a HashMap after calling mapValues below? I'm new to Scala, so it's very likely that I'm going about this all wrong, in which case feel free to suggest a completely different approach. (An apparently obvious solution would be to move the logic in the mapValues to inside the accum but that would be tricky in the larger app.)
#!/bin/sh
exec scala "$0" "$#"
!#
import scala.collection.immutable.HashMap
case class Quantity(val name: String, val amount: Double)
class PercentsUsage {
type PercentsOfTotal = HashMap[String, Double]
var quantities = List[Quantity]()
def total: Double = (quantities map { t => t.amount }).sum
def addQuantity(qty: Quantity) = {
quantities = qty :: quantities
}
def percentages: PercentsOfTotal = {
def accum(m: PercentsOfTotal, qty: Quantity) = {
m + (qty.name -> (qty.amount + (m getOrElse (qty.name, 0.0))))
}
val emptyMap = new PercentsOfTotal()
// The `emptyMap ++` at the beginning feels clumsy, but it does the
// job of giving me a PercentsOfTotal as the result of the method.
emptyMap ++ (quantities.foldLeft(emptyMap)(accum(_, _)) mapValues (dollars => dollars / total))
}
}
val pu = new PercentsUsage()
pu.addQuantity(new Quantity("A", 100))
pu.addQuantity(new Quantity("B", 400))
val pot = pu.percentages
println(pot("A")) // prints 0.2
println(pot("B")) // prints 0.8
Rather than using a mutable HashMap to build up your Map, you can just use scala collections' built in groupBy function. This creates a map from the grouping property to a list of the values in that group, which can then be aggregated, e.g. by taking a sum:
def percentages: Map[String, Double] = {
val t = total
quantities.groupBy(_.name).mapValues(_.map(_.amount).sum / t)
}
This pipeline transforms your List[Quantity] => Map[String, List[Quantity]] => Map[String, Double] giving you the desired result.
I have a function that calculates the left and right node values for some collection of treeNodes given a simple node.id, node.parentId association. It's very simple and works well enough...but, well, I am wondering if there is a more idiomatic approach. Specifically is there a way to track the left/right values without using some externally tracked value but still keep the tasty recursion.
/*
* A tree node
*/
case class TreeNode(val id:String, val parentId: String){
var left: Int = 0
var right: Int = 0
}
/*
* a method to compute the left/right node values
*/
def walktree(node: TreeNode) = {
/*
* increment state for the inner function
*/
var c = 0
/*
* A method to set the increment state
*/
def increment = { c+=1; c } // poo
/*
* the tasty inner method
* treeNodes is a List[TreeNode]
*/
def walk(node: TreeNode): Unit = {
node.left = increment
/*
* recurse on all direct descendants
*/
treeNodes filter( _.parentId == node.id) foreach (walk(_))
node.right = increment
}
walk(node)
}
walktree(someRootNode)
Edit -
The list of nodes is taken from a database. Pulling the nodes into a proper tree would take too much time. I am pulling a flat list into memory and all I have is an association via node id's as pertains to parents and children.
Adding left/right node values allows me to get a snapshop of all children (and childrens children) with a single SQL query.
The calculation needs to run very quickly in order to maintain data integrity should parent-child associations change (which they do very frequently).
In addition to using the awesome Scala collections I've also boosted speed by using parallel processing for some pre/post filtering on the tree nodes. I wanted to find a more idiomatic way of tracking the left/right node values. After looking at the answer from #dhg it got even better. Using groupBy instead of a filter turns the algorithm (mostly?) linear instead of quadtratic!
val treeNodeMap = treeNodes.groupBy(_.parentId).withDefaultValue(Nil)
def walktree(node: TreeNode) = {
def walk(node: TreeNode, counter: Int): Int = {
node.left = counter
node.right =
treeNodeMap(node.id)
.foldLeft(counter+1) {
(result, curnode) => walk(curnode, result) + 1
}
node.right
}
walk(node,1)
}
Your code appears to be calculating an in-order traversal numbering.
I think what you want to make your code better is a fold that carries the current value downward and passes the updated value upward. Note that it might also be worth it to do a treeNodes.groupBy(_.parentId) before walktree to prevent you from calling treeNodes.filter(...) every time you call walk.
val treeNodes = List(TreeNode("1","0"),TreeNode("2","1"),TreeNode("3","1"))
val treeNodeMap = treeNodes.groupBy(_.parentId).withDefaultValue(Nil)
def walktree2(node: TreeNode) = {
def walk(node: TreeNode, c: Int): Int = {
node.left = c
val newC =
treeNodeMap(node.id) // get the children without filtering
.foldLeft(c+1)((c, child) => walk(child, c) + 1)
node.right = newC
newC
}
walk(node, 1)
}
And it produces the same result:
scala> walktree2(TreeNode("0","-1"))
scala> treeNodes.map(n => "(%s,%s)".format(n.left,n.right))
res32: List[String] = List((2,7), (3,4), (5,6))
That said, I would completely rewrite your code as follows:
case class TreeNode( // class is now immutable; `walktree` returns a new tree
id: String,
value: Int, // value to be set during `walktree`
left: Option[TreeNode], // recursively-defined structure
right: Option[TreeNode]) // makes traversal much simpler
def walktree(node: TreeNode) = {
def walk(nodeOption: Option[TreeNode], c: Int): (Option[TreeNode], Int) = {
nodeOption match {
case None => (None, c) // if this child doesn't exist, do nothing
case Some(node) => // if this child exists, recursively walk
val (newLeft, cLeft) = walk(node.left, c) // walk the left side
val newC = cLeft + 1 // update the value
val (newRight, cRight) = walk(node.right, newC) // walk the right side
(Some(TreeNode(node.id, newC, newLeft, newRight)), cRight)
}
}
walk(Some(node), 0)._1
}
Then you can use it like this:
walktree(
TreeNode("1", -1,
Some(TreeNode("2", -1,
Some(TreeNode("3", -1, None, None)),
Some(TreeNode("4", -1, None, None)))),
Some(TreeNode("5", -1, None, None))))
To produce:
Some(TreeNode(1,4,
Some(TreeNode(2,2,
Some(TreeNode(3,1,None,None)),
Some(TreeNode(4,3,None,None)))),
Some(TreeNode(5,5,None,None))))
If I get your algorithm correctly:
def walktree(node: TreeNode, c: Int): Int = {
node.left = c
val c2 = treeNodes.filter(_.parentId == node.id).foldLeft(c + 1) {
(cur, n) => walktree(n, cur)
}
node.right = c2 + 1
c2 + 2
}
walktree(new TreeNode("", ""), 0)
Off-by-one errors are likely to occur.
Few random thoughts (better suited for http://codereview.stackexchange.com):
try posting that compiles... We have to guess that is a sequence of TreeNode:
val is implicit for case classes:
case class TreeNode(val id: String, val parentId: String) {
Avoid explicit = and Unit for Unit functions:
def walktree(node: TreeNode) = {
def walk(node: TreeNode): Unit = {
Methods with side-effects should have ():
def increment = {c += 1; c}
This is terribly slow, consider storing list of children in the actual node:
treeNodes filter (_.parentId == node.id) foreach (walk(_))
More concice syntax would be treeNodes foreach walk:
treeNodes foreach (walk(_))
I worked my way implementing a recursive version of selection and quick sort,i am trying to modify the code in a way that it can sort a list of any generic type , i want to assume that the generic type supplied can be converted to Comparable at runtime.
Does anyone have a link ,code or tutorial on how to do this please
I am trying to modify this particular code
'def main (args:Array[String]){
val l = List(2,4,5,6,8)
print(quickSort(l))
}
def quickSort(x:List[Int]):List[Int]={
x match{
case xh::xt =>
{
val (first,pivot,second) = partition(x)
quickSort (first):::(pivot :: quickSort(second))
}
case Nil => {x}
}
}
def partition (x:List[Int])=
{
val pivot =x.head
var first:List[Int]=List ()
var second : List[Int]=List ()
val fun=(i:Int)=> {
if (i<pivot)
first=i::first
else
second=i::second
}
x.tail.foreach(fun)
(first,pivot,second)
}
enter code here
def main (args:Array[String]){
val l = List(2,4,5,6,8)
print(quickSort(l))
}
def quickSort(x:List[Int]):List[Int]={
x match{
case xh::xt =>
{
val (first,pivot,second) = partition(x)
quickSort (first):::(pivot :: quickSort(second))
}
case Nil => {x}
}
}
def partition (x:List[Int])=
{
val pivot =x.head
var first:List[Int]=List ()
var second : List[Int]=List ()
val fun=(i:Int)=> {
if (i<pivot)
first=i::first
else
second=i::second
}
x.tail.foreach(fun)
(first,pivot,second)
} '
Language: SCALA
In Scala, Java Comparator is replaced by Ordering (quite similar but comes with more useful methods). They are implemented for several types (primitives, strings, bigDecimals, etc.) and you can provide your own implementations.
You can then use scala implicit to ask the compiler to pick the correct one for you:
def sort[A]( lst: List[A] )( implicit ord: Ordering[A] ) = {
...
}
If you are using a predefined ordering, just call:
sort( myLst )
and the compiler will infer the second argument. If you want to declare your own ordering, use the keyword implicit in the declaration. For instance:
implicit val fooOrdering = new Ordering[Foo] {
def compare( f1: Foo, f2: Foo ) = {...}
}
and it will be implicitly use if you try to sort a List of Foo.
If you have several implementations for the same type, you can also explicitly pass the correct ordering object:
sort( myFooLst )( fooOrdering )
More info in this post.
For Quicksort, I'll modify an example from the "Scala By Example" book to make it more generic.
class Quicksort[A <% Ordered[A]] {
def sort(a:ArraySeq[A]): ArraySeq[A] =
if (a.length < 2) a
else {
val pivot = a(a.length / 2)
sort (a filter (pivot >)) ++ (a filter (pivot == )) ++
sort (a filter(pivot <))
}
}
Test with Int
scala> val quicksort = new Quicksort[Int]
quicksort: Quicksort[Int] = Quicksort#38ceb62f
scala> val a = ArraySeq(5, 3, 2, 2, 1, 1, 9, 39 ,219)
a: scala.collection.mutable.ArraySeq[Int] = ArraySeq(5, 3, 2, 2, 1, 1, 9, 39, 21
9)
scala> quicksort.sort(a).foreach(n=> (print(n), print (" " )))
1 1 2 2 3 5 9 39 219
Test with a custom class implementing Ordered
scala> case class Meh(x: Int, y:Int) extends Ordered[Meh] {
| def compare(that: Meh) = (x + y).compare(that.x + that.y)
| }
defined class Meh
scala> val q2 = new Quicksort[Meh]
q2: Quicksort[Meh] = Quicksort#7677ce29
scala> val a3 = ArraySeq(Meh(1,1), Meh(12,1), Meh(0,1), Meh(2,2))
a3: scala.collection.mutable.ArraySeq[Meh] = ArraySeq(Meh(1,1), Meh(12,1), Meh(0
,1), Meh(2,2))
scala> q2.sort(a3)
res7: scala.collection.mutable.ArraySeq[Meh] = ArraySeq(Meh(0,1), Meh(1,1), Meh(
2,2), Meh(12,1))
Even though, when coding Scala, I'm used to prefer functional programming style (via combinators or recursion) over imperative style (via variables and iterations), THIS TIME, for this specific problem, old school imperative nested loops result in simpler code for the reader. I don't think falling back to imperative style is a mistake for certain classes of problems (such as sorting algorithms which usually transform the input buffer (like a procedure) rather than resulting to a new sorted one
Here it is my solution:
package bitspoke.algo
import scala.math.Ordered
import scala.collection.mutable.Buffer
abstract class Sorter[T <% Ordered[T]] {
// algorithm provided by subclasses
def sort(buffer : Buffer[T]) : Unit
// check if the buffer is sorted
def sorted(buffer : Buffer[T]) = buffer.isEmpty || buffer.view.zip(buffer.tail).forall { t => t._2 > t._1 }
// swap elements in buffer
def swap(buffer : Buffer[T], i:Int, j:Int) {
val temp = buffer(i)
buffer(i) = buffer(j)
buffer(j) = temp
}
}
class SelectionSorter[T <% Ordered[T]] extends Sorter[T] {
def sort(buffer : Buffer[T]) : Unit = {
for (i <- 0 until buffer.length) {
var min = i
for (j <- i until buffer.length) {
if (buffer(j) < buffer(min))
min = j
}
swap(buffer, i, min)
}
}
}
As you can see, rather than using java.lang.Comparable, I preferred scala.math.Ordered and Scala View Bounds rather than Upper Bounds. That's certainly works thanks to many Scala Implicit Conversions of primitive types to Rich Wrappers.
You can write a client program as follows:
import bitspoke.algo._
import scala.collection.mutable._
val sorter = new SelectionSorter[Int]
val buffer = ArrayBuffer(3, 0, 4, 2, 1)
sorter.sort(buffer)
assert(sorter.sorted(buffer))