Elegantly do a sum of object attributes in CoffeeScript - coffeescript

I have an array of items like so:
#items = [
{price: 12, quantity:1},
{price: 4, quantity:1},
{price: 8, quantity:1}
]
And I am looking for something like this:
sumPrice: ->
#items.sum (item) -> item.price * item.quantity
Or anything as close as possible to this, that makes it super-easy for everyone reading the code to understand whats happening.
So far I came up with:
sumPrice: ->
(items.map (a) -> a.price * a.quantity).reduce (a, b) -> a + b
contains too much functional magic
loses descriptiveness
And:
sumPrice: ->
sum = 0
for item in items
sum += item.price * item.quantity
sum
which can be understood by novice JS/Coffee programmers
feels a bit stupid
I love CoffeeScript so I hope there is a nicer solution to this & similar scenarios that I miss.

Functional style is not so bad. CoffeeScript allows you to prettify your code like this:
items
.map (item) ->
item.price * item.quantity
.reduce (x,y) ->
x+y
This code is easier for understanding than your one-liner.
If you don't like map you can use for instead. Like this:
(for item in items
item.price * item.quantity)
.reduce (x,y)->x+y
Or like this:
prods = for item in items
item.price * item.quantity
prods.reduce (x,y)->x+y
Or you can add your own sum() method for arrays:
Array::sum = -> #reduce (x,y)->x+y
(item.price * item.quantity for item in items).sum()

If you want to express the solution as #items.sum (item) -> item.price * item.quantity you can add a sum method to Array:
Array::sum = (fn = (x) -> x) ->
#reduce ((a, b) -> a + fn b), 0
sum = #items.sum (item) -> item.price * item.quantity
Notice that i'm passing 0 as the initial value of reduce so the fn callback is called for every array value.
If you don't like extending the builtin objects, i guess you could express the sum as a single reduce elegantly if you extract the logic of calculating the total price for a single array item in its own function:
itemPrice = (item) -> item.price * item.quantity
sum = items.reduce ((total, item) -> total + itemPrice item), 0

You can use destructuring to simplify the code slightly:
sumPrice: ->
sum = 0
sum += price * quantity for {price, quantity} in #items
sum
I don't think there's any way to get rid of the explicit initialization of sum. While Coffeescript's for loop syntax tends to help simplify code that would otherwise use map(), it doesn't really have anything analogous that simplifies reduce()-type operations, which is what sumPrice is doing here.
As mentioned in the comments, one advantage this solution has over a call to reduce() or sum() is that it avoids the overhead of creating and repeatedly calling a function.

sum = 0
value = (item) ->
item.price * item.quantity
sum += value(item) for item in #items

Related

scala call tuple element with variable

I'm new to scala and I'm trying to figure out how tuple works. I'm trying to call the xth element of a tuplle where x is a variable but it seems not to work, how should I do?
for (x <- 1 to 2; j <- 0 to (N-1)) yield((j, index._x), (x-1,index._x))
In particular the index._x seem to not work
It is possible to do this using the Product trait, though, as mentioned in the comment, this is not really a good idea or the intended way tuples are supposed to be used:
val indexed = index.productIterator.toIndexedSeq
for {
x <- 1 to 2
j <- 0 until N
} yield ((j, indexed(x-1)), (x-1, indexed(x-1))
or better yet (get rid of indexed access, it's yuky):
index.productIterator.take(2).toSeq.zipWithIndex
.flatMap { case (value, index) =>
(0 until N).map { j => ((j, value), (index, value)) }
}
I'll say it again though: there is about 99% chance there is a better way to do what you are actually trying to do. Tuples are meant for grouping data, not iterating over it (use collections for that).

Filtering a Scala List

I need to create function that takes double and returns new list, based on the first one, that includes absolute values of elements grom the first list that belongs to the range of <-5,12>. I need to use filtering. I have an idea, but it's not working. I'm sorry, maybe my question is easy, but I'm a begginer :)
var numbersReal = List(2.25, -1, -3, 7.32, 0.25, -6, 0, 2, 0, 1, 0, 2.99, 3.02, 0)
def magicFilter(list: List[Double]): List[Double] = {
var newList = List[Double]()
list.foreach {element => if (-5 <= element && element <= 12) newList += scala.math.abs(element) }
newList.toList
}
println(magicFilter(numbersReal))
Best Practice Solution
You can do this easily with a combination of
filter: keep only elements that satisfy a given predicate / condition. For us, it will be keeping only elements in [-5,12]
map: apply a function to every element. For us, it will be taking the absolute value.
numbersReal.filter(e => e >= -5 && e <= 12).map(math.abs)
Another way to achieve this in "one-shot" is to use collect which combines both filter and map:
numbersReal.collect { case e if e >= 5 && e <= 12 => math.abs(e) }
I personally find the first solution to be more readable in this particular case, but that's a matter of opinion.
Usually, these problems can be solved without resorting to a var or any mutable collection. Scala's collections are one of its greatest assets because they include a lot of these primitive operations, and most problems can be solved by combining them.
Note regarding your proposed solution
Your solution is not wrong per-se, but it is very error-prone to implement logic that is already part of collection methods like filter, map and collect. If you wanted to fix your approach, you just have to replace newList += ... with newList :+= .... This is because adding an element to an immutable List is done with list :+ element (or element +: list if you want to prepend). The list :+= element is syntactic sugar for list = list :+ element. Again, these are not constructs you should encounter very often, because this style is generally frowned-upon except if you know you have a very good reason to use mutability.

How to pair each element of a Seq with the rest?

I'm looking for an elegant way to combine every element of a Seq with the rest for a large collection.
Example: Seq(1,2,3).someMethod should produce something like
Iterator(
(1,Seq(2,3)),
(2,Seq(1,3)),
(3,Seq(1,2))
)
Order of elements doesn't matter. It doesn't have to be a tuple, a Seq(Seq(1),Seq(2,3)) is also acceptable (although kinda ugly).
Note the emphasis on large collection (which is why my example shows an Iterator).
Also note that this is not combinations.
Ideas?
Edit:
In my use case, the numbers are expected to be unique. If a solution can eliminate the dupes, that's fine, but not at additional cost. Otherwise, dupes are acceptable.
Edit 2: In the end, I went with a nested for-loop, and skipped the case when i == j. No new collections were created. I upvoted the solutions that were correct and simple ("simplicity is the ultimate sophistication" - Leonardo da Vinci), but even the best ones are quadratic just by the nature of the problem, and some create intermediate collections by usage of ++ that I wanted to avoid because the collection I'm dealing with has close to 50000 elements, 2.5 billion when quadratic.
The following code has constant runtime (it does everything lazily), but accessing every element of the resulting collections has constant overhead (when accessing each element, an index shift must be computed every time):
def faceMap(i: Int)(j: Int) = if (j < i) j else j + 1
def facets[A](simplex: Vector[A]): Seq[(A, Seq[A])] = {
val n = simplex.size
(0 until n).view.map { i => (
simplex(i),
(0 until n - 1).view.map(j => simplex(faceMap(i)(j)))
)}
}
Example:
println("Example: facets of a 3-dimensional simplex")
for ((i, v) <- facets((0 to 3).toVector)) {
println(i + " -> " + v.mkString("[", ",", "]"))
}
Output:
Example: facets of a 3-dimensional simplex
0 -> [1,2,3]
1 -> [0,2,3]
2 -> [0,1,3]
3 -> [0,1,2]
This code expresses everything in terms of simplices, because "omitting one index" corresponds exactly to the face maps for a combinatorially described simplex. To further illustrate the idea, here is what the faceMap does:
println("Example: how `faceMap(3)` shifts indices")
for (i <- 0 to 5) {
println(i + " -> " + faceMap(3)(i))
}
gives:
Example: how `faceMap(3)` shifts indices
0 -> 0
1 -> 1
2 -> 2
3 -> 4
4 -> 5
5 -> 6
The facets method uses the faceMaps to create a lazy view of the original collection that omits one element by shifting the indices by one starting from the index of the omitted element.
If I understand what you want correctly, in terms of handling duplicate values (i.e., duplicate values are to be preserved), here's something that should work. Given the following input:
import scala.util.Random
val nums = Vector.fill(20)(Random.nextInt)
This should get you what you need:
for (i <- Iterator.from(0).take(nums.size)) yield {
nums(i) -> (nums.take(i) ++ nums.drop(i + 1))
}
On the other hand, if you want to remove dups, I'd convert to Sets:
val numsSet = nums.toSet
for (num <- nums) yield {
num -> (numsSet - num)
}
seq.iterator.map { case x => x -> seq.filter(_ != x) }
This is quadratic, but I don't think there is very much you can do about that, because in the end of the day, creating a collection is linear, and you are going to need N of them.
import scala.annotation.tailrec
def prems(s : Seq[Int]):Map[Int,Seq[Int]]={
#tailrec
def p(prev: Seq[Int],s :Seq[Int],res:Map[Int,Seq[Int]]):Map[Int,Seq[Int]] = s match {
case x::Nil => res+(x->prev)
case x::xs=> p(x +: prev,xs, res+(x ->(prev++xs)))
}
p(Seq.empty[Int],s,Map.empty[Int,Seq[Int]])
}
prems(Seq(1,2,3,4))
res0: Map[Int,Seq[Int]] = Map(1 -> List(2, 3, 4), 2 -> List(1, 3, 4), 3 -> List(2, 1, 4),4 -> List(3, 2, 1))
I think you are looking for permutations. You can map the resulting lists into the structure you are looking for:
Seq(1,2,3).permutations.map(p => (p.head, p.tail)).toList
res49: List[(Int, Seq[Int])] = List((1,List(2, 3)), (1,List(3, 2)), (2,List(1, 3)), (2,List(3, 1)), (3,List(1, 2)), (3,List(2, 1)))
Note that the final toList call is only there to trigger the evaluation of the expressions; otherwise, the result is an iterator as you asked for.
In order to get rid of the duplicate heads, toMap seems like the most straight-forward approach:
Seq(1,2,3).permutations.map(p => (p.head, p.tail)).toMap
res50: scala.collection.immutable.Map[Int,Seq[Int]] = Map(1 -> List(3, 2), 2 -> List(3, 1), 3 -> List(2, 1))

Is it possible to update a variable in foldLeft function based on a condition?

I am trying to write scala code which gives maximum sum from contiguous sub-array from the given array. For example, val arr= Array(-2, -3, 4, -1, -2, 1, 5, -3). In this array I need to get maximum contiguous sub-array sum i.e 4+(-1)+(-2)+(1)+5 = 7. I wrote following code for getting this result.
scala> arr.foldLeft(0) { (currsum,newnum) => if((currsum+newnum)<0) 0 else { if(currsum<(currsum+newnum)) (currsum+newnum) else currsum }}
res5: Int = 10
but deviated from actual result as I am unable to update the maximum_so_farvalue as the counting/summation goes on. Since I have used foldLeft to do this functionality, is there any possibility to update the maximum_so_farvariable only when sum of contiguous sub array elements is greater than previous max_sum?
reference link for better understanding of scenario
Well, obviously you have to propagate two values along your input data for this computation, just as you would need to do in the imperative case:
arr.foldLeft((0,0)){
case ((maxSum, curSum), value) => {
val newSum = Math.max(0, curSum + value)
(Math.max(maxSum, newSum), newSum)
}
}._1
An other way would be to compute the intermediate results (lazily if you want) and then select the maximum:
arr.toIterator.scanLeft(0){
case (curSum, value) =>
Math.max(0, curSum + value)
}.max

Nice way to assign min max variables / deconstruct an array?

I'm looking for an expression to assign the smallest and largest of 2 numbers to variables.
There are several approaches that work
let a = 2
let b = 1
let (min, max) = (min(a, b), max(a, b))
But I wanted something a bit more flexible, for example
let sorted = [a, b].sorted{$0 < $1}
let (min, max) = (sorted.first, sorted.last)
But it's 2 lines... I was looking for something like:
let (min, max) = [a, b].sorted{$0 < $1}
But that doesn't compile, I think because it's not possible to deconstruct arrays, at least in this way, and there doesn't seem to be a clean/meaningful way to convert it to a tuple.
What am I missing? I know there's somewhere an elegant expression for this.
I’d just do a variant of your (pre-edit) first one:
let (min,max) = a < b ? (a,b) : (b,a)
If you do this a lot, you could wrap this in a generic function to make it a bit neater:
func minmax<T: Comparable>(a: T, b: T) -> (T,T) {
return a < b ? (a,b) : (b,a)
}
Which makes this quite nice and readable at the call site:
let (min,max) = minmax(a, b)