CoffeeScript: Assigning values to object - coffeescript

Let´s say I have following object:
dict = { a: 1, b: 2, c: 3 }
following works perfectly:
{a, b} = dict
// -> a = 1
// -> b = 2
Now I want to manipulate those numbers and write it back to the object and clearly following line does not work:
// some manipulations
dict = {a, b}
Obviously I have overwritten the dict object. What I essentially wanted to do is assign dict.a = a and dict.b = b with dict.c staying as it is.
Is it possible to achieve my goal with some sort of a short notation?

You can extract a slice of an object into separate local variables using:
{a, b} = dict
but there's no way to assign to a slice of an object, i.e. you can't do things like this:
dict{a, b} = [ x, y ]
as a shortcut for
dict.a = x
dict.b = y
You can't even extract an object slice into a new object with things like this:
obj = dict{a, b}
you have to do it in two steps:
{ a, b } = dict
obj = { a, b }
Destructured assignments work well to pull things out of objects but they're not that useful for putting things back into objects. I think the closest you can get is to use a destructured array assignment:
[ dict.a, dict.b ] = [ a, b ]
If you're working with several keys, then you could put the keys in an array and do the slicing and merging with loops (possibly wrapped in helper functions):
slice = (obj, keys...) ->
s = { }
s[k] = obj[k] for k in keys
s
merge = (dest, src) ->
dest[k] = src[k] for k of src
return
keys = [ 'a', 'b' ]
dict = { a: 1, b: 2, c: 3 }
s = slice(dict, keys...)
s.a += 6
s.b += 6
merge(dict, s)
# dict is now { a: 7, b: 8, c: 3 }
Or just use the Underscore, jQuery, ... utility functions.

In pure coffeescript:
extend = (a, others...) ->
for o in others
a[key] = val for key, val of o
a
dict = { a: 1, b: 2, c: 3 }
{a, b} = dict
a = 5
b = 8
extend dict, {a, b}
console.log dict
#dict = { a: 5, b: 8, c: 3 }

Assuming you are using underscore.js, I would do this:
dict = { a: 1, b: 2, c: 3 }
{a, b} = dict
...
dict = _.extend dict, {a:a, b:b}
As asawyer points out, there's a similar extend function in jQuery too.

Related

How to use string.split() without foreach()?

Write a program in Scala that reads an String from the keyboard and counts the number of characters, ignoring if its UpperCase or LowerCase
ex: Avocado
R: A = 2; v = 1; o = 2; c = 1; d = 2;
So, i tried to do it with two fors iterating over the string, and then a conditional to transform the character in the position (x) to Upper and compare with the character in the position (y) which is the same position... basically i'm transforming the same character so i can increment in the counter ex: Ava -> A = 2; v = 1;
But with this logic when i print the result it comes with:
ex: Avocado
R: A = 2; v = 1; o = 2; c = 1; a = 2; d = 1; o = 2;
its repeting the same character Upper or Lower in the result...
so my teacher asked us to resolve this using the split method and yield of Scala but i dunno how to use the split without forEach() that he doesnt allow us to use.
sorry for the bad english
object ex8 {
def main(args: Array[String]): Unit = {
println("Write a string")
var string = readLine()
var cont = 0
for (x <- 0 to string.length - 1) {
for (y <- 0 to string.length - 1) {
if (string.charAt(x).toUpper == string.charAt(y).toUpper)
cont += 1
}
print(string.charAt(x) + " = " + cont + "; ")
cont = 0
}
}
}
But with this logic when i print the result it comes with:
ex: Avocado
R: A = 2; V = 1; o = 2; c = 1; a = 2; d = 1; o = 2;
Scala 2.13 has added a very handy method to cover this sort of thing.
inputStr.groupMapReduce(_.toUpper)(_ => 1)(_+_)
.foreach{case (k,v) => println(s"$k = $v")}
//A = 2
//V = 1
//C = 1
//O = 2
//D = 1
It might be easier to group the individual elements of the String (i.e. a collection of Chars, made case-insensitive with toLower) to aggregate their corresponding size using groupBy/mapValues:
"Avocado".groupBy(_.toLower).mapValues(_.size)
// res1: scala.collection.immutable.Map[Char,Int] =
// Map(a -> 2, v -> 1, c -> 1, o -> 2, d -> 1)
Scala 2.11
Tried with classic word count approach of map => group => reduce
val exampleStr = "Avocado R"
exampleStr.
toLowerCase.
trim.
replaceAll(" +","").
toCharArray.map(x => (x,1)).groupBy(_._1).
map(x => (x._1,x._2.length))
Answer :
exampleStr: String = Avocado R
res3: scala.collection.immutable.Map[Char,Int] =
Map(a -> 2, v -> 1, c -> 1, r -> 1, o -> 2, d -> 1)

Assign same value to multiple variables in Scala

I have 3 variables that have already been initialized, and I want to assign a new value to all three of them. e.g.
var a = 1
var b = 2
var c = 3
and I want to reassign them to the same value e.g.
a = b = c = 4
But the above expression is invalid. Is there a right way to do this in Scala?
It is possible to slightly shorten the var definition code as follows
var (a, b, c) = (1, 2, 3)
This works because of extractor objects in scala. A tuple of 3 is extracted into 3 components it was created with.
But following does not work becase the extraction is applied on val or var definitions.
(a, b, c) = (4, 4, 4)
You can do this:
var Seq(a, b, c) = Seq.fill(3)(4)
As with Ivan's solution, this only works when declaring vars or vals, not when reassigning. Since the second parameter is computed for each element, it even works well for mutable objects:
import scala.collection.mutable.ListBuffer
var Seq(a, b, c) = Seq.fill(3)(ListBuffer[Int]())
a += 1 // Only modifies a, not b or c.
By contrast, something like a = b = c = [] will only create one list in most programming languages (e.g. Python, JavaScript, Java). If you don't want to create your object each time (perhaps because it is immutable and creation is expensive), declare it as val first to prevent this behavior:
val largeObject = ???
var Seq(a, b, c) = Seq.fill(3)(largeObject)

Nim operator overloading

Just started programming in the Nim language (which I really like so far). As a learning exercise I am writing a small matrix library. I have a bunch more code, but I'll just show the part that's relevant to this question.
type
Matrix*[T; nrows, ncols: static[int]] = array[0 .. (nrows * ncols - 1), T]
# Get the index in the flattened array corresponding
# to row r and column c in the matrix
proc index(mat: Matrix, r, c: int): int =
result = r * mat.ncols + c
# Return the element at r, c
proc `[]`(mat: Matrix, r, c: int): Matrix.T =
result = mat[mat.index(r, c)]
# Set the element at r, c
proc `[]=`(mat: var Matrix, r, c: int, val: Matrix.T) =
mat[mat.index(r, c)] = val
# Add a value to every element in the matrix
proc `+=`(mat: var Matrix, val: Matrix.T) =
for i in 0 .. mat.high:
mat[i] += val
# Add a value to element at r, c
proc `[]+=`(mat: var Matrix, r, c: int, val: Matrix.T) =
mat[mat.index(r, c)] += val
# A test case
var mat: Matrix[float, 3, 4] # matrix with 3 rows and 4 columns
mat[1, 3] = 7.0
mat += 1.0
# add 8.0 to entry 1, 3 in matrix
`[]+=`(mat, 1, 3, 8.0) # works fine
All this works fine, but I'd like to be able to replace the last line with something like
mat[1, 3] += 4.0
This won't work (wasn't expecting it to either). If I try it, I get
Error: for a 'var' type a variable needs to be passed
How would I create an addition assignment operator that has this behavior? I'm guessing I need something other than a proc to accomplish this.
There are two ways you can do this:
Overload [] for var Matrix and return a var T (This requires the current devel branch of Nim):
proc `[]`(mat: Matrix, r, c: int): Matrix.T =
result = mat[mat.index(r, c)]
proc `[]`(mat: var Matrix, r, c: int): var Matrix.T =
result = mat[mat.index(r, c)]
Make [] a template instead:
template `[]`(mat: Matrix, r, c: int): expr =
mat[mat.index(r, c)]
This causes a problem when mat is not a value, but something more complex:
proc x: Matrix[float, 2, 2] =
echo "x()"
var y = x()[1, 0]
This prints x() twice.

CoffeeScript: assigning multiple properties to an initialised object

w = {c: true}
w =
a: 4
b: true
console.log w
I expect the result w to be {a: 4, b: true, c: true}, but I get {a: 4, b: true}.
How can I do multiple assignments to object properties without loosing already set properties?
CoffeeScript: assigning multiple properties to an initialised object has been the best answer so far.
But if you only want to add a few properties to an object you can just do:
w = {c: true}
w.a = 4
w['b'] = true # alternative notation
Also, this question is more about JavaScript than CoffeeScript.
I don't think it can be done directly. I believe, you need to iterate:
w = {c: true}
temp =
a: 4
b: true
w[k] = v for k,v of temp
console.log w
w = {c: true}
w[i] = v for i,v of {
a: 4
b: true
}
console.log w

How to assign the same value to more var in scala

To instantiate the variables can do so:
scala> var (a, b, c) = (0, 0, 23)
a: Int = 0
b: Int = 0
c: Int = 23
but if I wanted to do such a thing?
scala> a = b = c
<console>:10: error: type mismatch;
found : Unit
required: Int
a = b = c
^
how can I do?
Thanks
var a,b,c = 0
should do the trick.
You can't do a = b = c because a has already been defined as a Int var, and with the a = b = c statement you are giving a a Unit, 'b = c'.
When you assign a value to a variable in Scala you don't get as a result the value assigned.
In other languages b = c would be evaluated to 23, the value of c. In Scala b = c is just a Unit, writing a = b = c is exactly like writing a = (b = c), hence the error.