Kotlin: initialize 2D array - arrays

I am in a loop, reading 2 columns from a file. I read R, T combinations, 50 times. I want R and T to be in an array so I can look up the Nth pair of R, T later in a function. How do I put the R, T pairs in an array and look up the, say, 25th entry later in a function?
For example:
for (nsection in 1 until NS+1) {
val list: List<String> = lines[nsection + 1].trim().split("\\s+".toRegex())
val radius = list[0].toFloat()
println("Radius = $radius")
val twist = list[8].toFloat()
println("twist = $twist")
}
Would like to pull radius and twist pairs from a table in a function later. NS goes up to 50 so far.

You can use map() on your range iterator to produce a List of what you want.
val radiusTwistPairs: List<Pair<Float, Float>> = (1..NS).map { nsection ->
val list = lines[nsection + 1].trim().split("\\s+".toRegex())
val radius = list[0].toFloat()
println("Radius = $radius")
val twist = list[8].toFloat()
println("twist = $twist")
radius to twist
}
Or use an Array constructor:
val radiusTwistPairs: Array<Pair<Float, Float>> = Array(NS) { i ->
val list = lines[i + 2].trim().split("\\s+".toRegex())
val radius = list[0].toFloat()
println("Radius = $radius")
val twist = list[8].toFloat()
println("twist = $twist")
radius to twist
}

Related

How to Multiply Each element of an array multiply by each element of Next array in Swift?

I had two Arrays.
let quntityArr = ["1","3","4","7"]
let priceArr = ["£129.95", "£179.95","£169.95","£199.85"]
I want to multiply these both Arrays in the following way
let totalArr = ["1*£129.95", "3*£179.95", "4*£169.95", "7*£199.85"]
Here I want to calculate each price with those product quantities.
You need
let quntityArr:[Double] = [1,3,4,7]
let priceArr = [129.95, 179.95,169.95,199.85]
let totalArr = zip(quntityArr, priceArr).map { "£\($0 * $1)" }
print(totalArr)
Assuming your input data is provided as array of String.
1. Input Data
let quntityArr = ["1","3","4","7"]
let priceArr = ["£129.95", "£179.95","£169.95","£199.85"]
2. Convert input data in array of Int and Double
let quantities = quntityArr
.compactMap(Int.init)
let prices = priceArr
.map { $0.dropFirst() }
.compactMap (Double.init)
3. Verify no input value has been discarded
assert(quntityArr.count == quantities.count)
assert(priceArr.count == prices.count)
4. Do the math
let results = zip(quantities, prices).map { Double($0) * $1 }.map { "£\($0)"}
5. Result
["£129.95", "£539.8499999999999", "£679.8", "£1398.95"]

Loop through array and get row number for each element

I am quite new to Google Script, I'm learning on the job.
I have a range of data as a variable. It's only one column, column F in this case, but there are empty cells between values. I have a working script (got it from here earlier), which only loops through the cells with values in them. So lets say value1 is in F5, value2 is in F13, it's all random and always changing.
I'm trying to get the row number for these values, so that script should give back "5" for value1 and "13" for value2, ideally together with the value itself.
So far, that's what I have and I can not seem to progress further.
var sourceID = "sourceID";
var main = SpreadsheetApp.openById("mainID");
var mainsheet = main.getSheetByName("Lab Data");
var sourcesheet = source.getSheetByName("sheet name");
var dataRange = sourcesheet.getDataRange(); // range full sheet
var values = dataRange.getValues(); // values full sheet
var SWrowss = findCellForSW(); // getting start row from another function
var CQrowss = findCellForCQ(); // getting last row from another function
var noRows = CQrowss - SWrowss; // gets number of rows in range
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues(); // range we need, column F
// get rid of empty cells from range - copied script from stack overflow
var cResult = colss.reduce(function(ar, e) {
if (e[0]) ar.push(e[0])
return ar;
}, []);
Logger.log("cResult: " + cResult); // cResult contains all sub headers - no empty cells
// gets element's position in array
for(var b = 0; b < cResult.length; b++){
var position = b+1;
Logger.log("pos " + position);
} // end for
If you want to know the row number, I would propose you a different approach
Just loop through your values and retrieve the position of the ones that are not empty:
...
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rows = [];
var calues = [];
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
var row = SWrowss+b+1;
rows.push(row);
var value = colss[b][0];
values.push(value);
}
}
...
With the other solution you can build a single object that can do the conversion for you very quickly.
var colss = sourcesheet.getRange(SWrowss,6,noRows,1).getValues();
var rvObj={};
for(var b = 0; b < colss.length; b++){
if(colss[b][0] != "" && colss[b][0] != " "){
rvObj[colss[b][0]]=SWrowss+b+1;
}
}
With rvObj now you can get any row with var row = rvObj[value];

Godot 3.1 Invalid get'index '16' (on base:Array)

Invalid get'index '16' (on base:Array).
Hi Im getting the above message when the player attempts to moves outside of the
array size (tile size).
The error occurs on line 54:
grid[new_grid_pos.x][new_grid_pos.y] = ENTITY_TYPES.PLAYER
Im stuck on how to fix it.
regards
Jason
extends TileMap
var tile_size = get_cell_size()
var half_tile_size = tile_size / 2
enum ENTITY_TYPES {PLAYER, OBSTACLE, COLLECTIBLE}
var grid_size = Vector2(16,16)
var grid = []
onready var Obstacle = preload("res://scenes/Obstacle.tscn")
func _ready():
# Creates grid array of grid_size
for x in range(grid_size.x):
grid.append([])
for y in range(grid_size.y):
grid[x].append(null)
print(ENTITY_TYPES)
# Create obstacle positions array
var positions = []
# create 5 obstacles
for n in range(5):
# random positions constrained to grid_size
var grid_pos = Vector2(randi() % int(grid_size.x),randi() % int(grid_size.y))
#check random posisitions not already in array before adding new one
if not grid_pos in positions:
positions.append(grid_pos)
for pos in positions:
var new_obstacle = Obstacle.instance()
new_obstacle.position = (map_to_world(pos) + half_tile_size)
grid[pos.x][pos.y] = ENTITY_TYPES.OBSTACLE
add_child(new_obstacle)
func is_cell_vacant(pos, direction):
# Return true if cell is vaccant, else false
var grid_pos = world_to_map(pos) + direction
# world Boundaries
if grid.pos.x < grid_size.x and grid_pos.x >= 0:
if grid.pos.y < grid_size.y and grid_pos.y >= 0:
#return true if grid[grid_pos.x][grid_pos.y] == null else false
return grid[grid_pos.x][grid_pos.y] == null
return false
func update_child_pos(child_node):
# Move a child to a new position in the grid array
# Returns the new target world position of the child
var grid_pos = world_to_map(child_node.position)
grid[grid_pos.x][grid_pos.y] = null
var new_grid_pos = grid_pos + child_node.direction
grid[new_grid_pos.x][new_grid_pos.y] = ENTITY_TYPES.PLAYER
var target_pos = (map_to_world(new_grid_pos) + half_tile_size)
return target_pos
pass
You are receiving the error because you are exceeding the arrays elements.
To avoid it, either make the grid bigger or make it so that the player cannot leave the grid.
If you want the player to be able to leave the grid, then you will probably have to create an if condition:
if player_in_grid: grid[new_grid_pos.x][new_grid_pos.y] = ENTITY_TYPES.PLAYER.

Why I cannot update an array in cluster mode but could in pseudo-distributed

I wrote a spark program in scala, of which the main codes are:
val centers:Array[(Vector,Double)] = initCenters(k)
val sumsMap:Map(int,(vector,int))= data.mapPartitions{
***
}.reduceByKey(***).collectAsMap()
sumsMap.foreach{case(index,(sum,count))=>
sum/=count
centers(index)=(sum,sum.norm2())
}
the origin codes are:
val centers = initCenters.getOrElse(initCenter(data))
val br_centers = data.sparkContext.broadcast(centers)
val trainData = data.map(e => (e._2, e._2.norm2)).cache()
val squareStopBound = stopBound * stopBound
var isConvergence = false
var i = 0
val costs = data.sparkContext.doubleAccumulator
while (!isConvergence && i < maxIters) {
costs.reset()
val res = trainData.mapPartitions { iter =>
val counts = new Array[Int](k)
util.Arrays.fill(counts, 0)
val partSum = (0 until k).map(e => new DenseVector(br_centers.value(0)._1.size))
iter.foreach { e =>
val (index, cost) = KMeans.findNearest(e, br_centers.value)
costs.add(cost)
counts(index) += 1
partSum(index) += e._1
}
counts.indices.filter(j => counts(j) > 0).map(j => (j -> (partSum(j), counts(j)))).iterator
}.reduceByKey { case ((s1, c1), (s2, c2)) =>
(s1 += s2, c1 + c2)
}.collectAsMap()
br_centers.unpersist(false)
println(s"cost at iter: $i is: ${costs.value}")
isConvergence = true
res.foreach { case (index, (sum, count)) =>
sum /= count
val sumNorm2 = sum.norm2()
val squareDist = math.pow(centers(index)._2, 2.0) + math.pow(sumNorm2, 2.0) - 2 * (centers(index)._1 * sum)
if (squareDist >= squareStopBound) {
isConvergence = false
}
centers.update(index,(sum, sumNorm2))
}
i += 1
}
when these run in a pseudo-distributed mode in IDEA, I get the centers updated, while when I get these run on a spark cluster, I do not get the centers updated.
LostInOverflow's answer is correct, but not especially descriptive as to what's going on.
Here are some important properties of your code:
declare an array centers
broadcast this array as br_centers
update centers iteratively
So how is this going wrong? Well, broadcasts are static. If I write:
val a = Array(1,2,3)
val aBc = sc.broadcast(a)
a(0) = 67
and access aBc.value(0), I'm going to get different results depending on whether this code was run on the driver JVM or not. Broadcasting takes an object, torrents it across the network to each node, and creates a new reference in each JVM. This reference exists as it did when the base object was broadcasted, and it is NOT updated in real time as you mutate the base object.
What's the solution? I think moving the broadcast inside the while loop so that you broadcast the updated centers should work:
while (!isConvergence && i < maxIters) {
val br_centers = data.sparkContext.broadcast(centers)
...
Please check Understanding closures section in the programming guide.
Spark is a distributed system and behavior of the code you've shown is simply undefined. It works in local mode only by accident because it executes everything in a single JVM.

Swift: Array map or reduce, enumerate with index

I have an array of values [CGFloat] and array of days [CGFloat] with which each value is associated (the time is also important so the days array is a decimal value).
Each day has between 0 and n values. (n typically less than 5 or 6)
I want to find the mean value for each day, so after the calculations I would like to have an array of means [CGFloat] and an array of days [CGFloat], or a dictionary of the two combined or an array of [CGPoint]. I am fairly certain this can be done with either a mapping or reducing or filter function, but I'm having trouble doing so.
For instance
the third day might look like [2.45, 2.75, 2.9]
with associated values [145.0, 150.0, 160.0]
And I would like to end with day[2] = 2.7
and value[2] = 151.7
or
[CGPoint(2.7, 151.7)] or [2.7 : 151.7]
Can anyone offer guidance?
Some code:
let xValues : [CGFloat] = dates.map{round((CGFloat($0.timeIntervalSinceDate(dateZero))/(60*60*24))*100)/100}
let yValues : [CGFloat] = valueDoubles.map{CGFloat($0)}
//xValues and yValues are the same length
var dailyMeans = [CGFloat]()
var xVals = [CGFloat]()
let index = Int(ceil(xValues.last!))
for i in 0..<index{
let thisDay = xValues.enumerate().filter{$0.element >= CGFloat(i) && $0.element < CGFloat(i+1)}
if thisDay.count > 0{
var sum : CGFloat = 0
var day : CGFloat = 0
for i in thisDay{
sum += yValues[i.index]
day += xValues[i.index]
}
dailyMeans.append(sum/CGFloat(thisDay.count))
xVals.append(day/CGFloat(thisDay.count))
}
}
The above code works, but also has to do that enumerate.filter function values.count * days.last times. So for 40 days and 160 readings.. like 6500 times. And I'm already using way too much processing power as it is. Is there a better way to do this?
edit: forgot a line of code defining index as the ceiling of xValues.last
This has been seen 1000 times so I thought I would update with my final solution:
var daySets = [Int: [CGPoint]]()
// points is the full array of (x: dayTimeInDecimal, y: value)
for i in points {
let day = Int(i.x)
daySets[day] = (daySets[day] ?? []) + [i]
}
let meanPointsEachDay = daySets.map{ (key, value) -> CGPoint in
let count = CGFloat(value.count)
let sumPoint = value.reduce(CGPoint.zero, {CGPoint(x: $0.x + $1.x, y: $0.y + $1.y)})
return CGPoint(x: sumPoint.x/count, y: sumPoint.y/count)
}
// must be sorted by 'day'!!!
let arrA0 = [2.45, 2.75, 2.9, 3.1, 3.2, 3.3]
// associated values
let arrA1 = [145.0, 150.0, 160.0, 245.0, 250.0, 260.0]
let arr = Array(zip(arrA0, arrA1))
// now i have an array of tuples, where tuple.0 is key and tuple.1 etc. is associated value
// you can expand the tuple for as much associated values, as you want
print(arr)
// [(2.45, 145.0), (2.75, 150.0), (2.9, 160.0), (3.1, 245.0), (3.2, 250.0), (3.3, 260.0)]
// now i can perform my 'calculations' the most effective way
var res:[Int:(Double,Double)] = [:]
// sorted set of Int 'day' values
let set = Set(arr.map {Int($0.0)}).sort()
// for two int values the sort is redundant, but
// don't be depend on that!
print(set)
// [2, 3]
var g = 0
var j = 0
set.forEach { (i) -> () in
var sum1 = 0.0
var sum2 = 0.0
var t = true
while t && g < arr.count {
let v1 = arr[g].0
let v2 = arr[g].1
t = i == Int(v1)
if t {
g++
j++
} else {
break
}
sum1 += v1
sum2 += v2
}
res[i] = (sum1 / Double(j), sum2 / Double(j))
j = 0
}
print(res)
// [2: (2.7, 151.666666666667), 3: (3.2, 251.666666666667)]
see, that every element of your data is process only once in the 'calculation', independent from size of 'key' set size
use Swift's Double instead of CGFloat! this increase the speed too :-)
and finally what you are looking for
if let (day, value) = res[2] {
print(day, value) // 2.7 151.666666666667
}

Resources