CFSCRIPT - For loop increments the index wrong - for-loop

I might have been found a bug in ColdFusion 2016.
I have two functions. The first one has a loop which iterates from 1 to n and pushes the return value of the second function which is also an array into an array. I noticed that;
index value is 1,
calling function and pushing the value into the array,
and index value is the end value of the loop.
Is this a bug?
<cfscript>
public array function fnc1(required array p1, required array p2, required numeric pSize, required numeric qSize, required numeric dSize){
iterationNum = pSize/2;
point = randRange(1, qSize-1);
for(i = 1; i <= iterationNum; i++){
writeOutput(i); // prints: 1
pop[i] = fnc2(p1[i], p2[i], point);
writeOutput(i); // prints: iterationNum value
writeDump(var = pop[i], label = "pop-"&i);
}
writeDump(var = pop, label="pop");
}
public array function fnc2(required array p1, required array p2, required numeric point){
n = arrayLen(p1);
concatArr = arrayNew(1);
for(i = 1; i <= point; i++){
concatArr[i] = p1[i];
}
for(i = point + 1; i <= n; i++){
concatArr[i] = p2[i];
}
writeDump(var=concatArr, label="Concated Array");
return concatArr;
}
</cfscript>

The default scope of a variable inside of a cfc is not function only. But rather it is cfc wide. This is often problematic.
Similarly, the default scope of a variable outside of a cfc is request wide. This is often useful.
Two approaches
There are two approaches to limit the scope of a variable inside of a cfc. One is to use the keyword var, the other is the use local.
It is a long story as to how they are different. The sample solution below uses var throughout. If you want to know more about var vs local., click here: Scoping: Local vs Var
<cfscript>
public array function fnc1(required array p1, required array p2, required numeric pSize, required numeric qSize, required numeric dSize){
var iterationNum = pSize/2;
var point = randRange(1, qSize-1);
for(var i = 1; i <= iterationNum; i++){
writeOutput(i); // prints: 1
pop[i] = fnc2(p1[i], p2[i], point);
writeOutput(i); // prints: iterationNum value
writeDump(var = pop[i], label = "pop-"&i);
}
writeDump(var = pop, label="pop");
}
public array function fnc2(required array p1, required array p2, required numeric point){
var n = arrayLen(p1);
var concatArr = arrayNew(1);
for(var i = 1; i <= point; i++){
concatArr[i] = p1[i];
}
for(var ii = point + 1; ii <= n; ii++){
concatArr[ii] = p2[ii];
}
writeDump(var=concatArr, label="Concated Array");
return concatArr;
}
</cfscript>

Related

Best way to sort a list of lines for connectivity

I have a long list of lines in (possibly) random order. So basically:
struct Line
{
Vector StartPos;
Vector EndPos;
};
Now I'm looking for an efficient way to sort these lines so that they are sorted into spans. I.E. if line A's startpos matches Line B's endpos, it gets moved into the list immediately after line B. If nothing matches, it just goes to the end of the list to start a new span.
Right now I'm doing it brute force-- setting a flag variable if anything was changed, and if anything changed, sorting it again. This produces gigantically exponential iterations. Is there any faster way to optimize this so that I could conceivably keep the iterations down to listsize^listsize?
If you do not have lines that start or end at the same point maybe you can use dictionaries to reduce the look ups. Something like:
public class Line
{
public Point StartPos;
public Point EndPos;
public bool isUsed = false;
};
and then 1) create a dictionary with the key the endPos and the value the index of the element in you list, 2) for each element of the list follow the link using the dictionary. Something like:
List<List<Line>> result = new List<List<Line>>();
Dictionary<Point,int> dic= new Dictionary<Point,int>();
for (int kk = 0; kk < mylines.Count; kk++)
{
dic[mylines[kk].EndPos] = kk;
}
for (int kk = 0; kk < mylines.Count; kk++)
{
if (mylines[kk].isUsed == false)
{
var orderline= new List<Line>();
orderline.Add(mylines[kk]);
int mm = kk;
while (dic.ContainsKey(mylines[mm].EndPos))
{
mm = dic[mylines[mm].EndPos];
mylines[mm].isUsed = true;
orderline.Add(mylines[mm]);
}
result.Add(orderline);
}
}

Do I count Math.max in a Big O Runtime?

I have trouble in understanding weather or not using Math.max should be counted as a loop, therefore should be included in calculating Big O runtime.
I assume for the Math.max to find the max value it has to loop and compare through all the values it was provided. Therefore it is actually looping.
My code in JS:
function getWaterCapacityPerSurface(surface){
let waterAmount = 0;
// full loop
for(let i = 1; i < surface.length - 1; i++){
const current = surface[i];
// I assume each slice is counted as a half of the full loop
const leftSlice = surface.slice(0, (i - 1 < 0 ? 0 : i));
const rightSlice = surface.slice(i + 1, surface.length);
// I assume each Math.max is counted as a half of the full loop
const leftBound = Math.max(...leftSlice);
const rightBound = Math.max(...rightSlice);
const canWaterStay = leftBound > current && rightBound > current;
const currentBound = Math.min(leftBound, rightBound);
const waterLevel = currentBound - current;
if(canWaterStay) waterAmount += waterLevel;
}
return waterAmount;
}
console.log(getWaterCapacityPerSurface([4,2,1,3,0,1,2]));
// returns 6
Is Big O runtime O(N(N+N)) or O(N(N))?
I assume in this case it doesn't really matter because we drop constants and at the end it is going to be O(N(N+N)) = O(N(2N)) = O(N(N)) = O(N²)
But I just would like to know weather I should count Math.max/Math.min as a loop for future reference.
Yes, if you pass a list of arguments of length n to Math.max(), then it is an O(n) operation. Math.max() iterates through every argument. See more info in the specification.

Loops and iterations

Is there a way that a function has 2 options of return and the option of return is chosen after a certain interval of iterations?
example:
a function that swaps from "a" to "b" and "b" to "a" after 4 iterations returns:
a
a
a
a
b
b
b
b
a
a
a
a
b
b
b
b
.
.
.
Edit I did something like this to solve the problem:
var counter = 0;
var state = true;
var changeState = function(){
var x = 0
while(x != 12){
if(counter == 4){
counter = 0;
state = !state;
}
if (state){
console.log("a");
} else {
console.log("b")
}
counter += 1;
x += 1
}
}
changeState();
You will need to have a stateful function, as it needs to somehow remember something from previous call(s) that were made to it. This is a so-called side effect, and means that the function is not pure.
For the example you have given, the function would need to know (i.e. have a state with) the number of previous calls (modulo 8), or the previous four returned values, or some mix of this information.
How such a function is implemented, depends on the programming language.
In object oriented programming languages you would create a class with the function as method, and a property reflecting that state. When the function is called, it also updates the state. For instance, in Java:
class MyClass {
int callCount = 0;
char myFunction() {
return "aaaabbbb".charAt(this.callCount++ % 8);
}
}
You would call the function repeatedly like so:
MyClass obj = new MyClass();
for (int i = 0; i < 10; i++) {
System.out.println(obj.myFunction());
}
In JavaScript you could do the same, or you could create a closure:
function createFunction() {
let callCount = 0;
return function myFunction() {
return "aaaabbbb"[callCount++ % 8];
}
}
let myFunction = createFunction();
for (let i = 0; i < 10; i++) {
console.log(myFunction());
}
In Python you can do the same, but it allows also to use default arguments (which are only initialised at function definition time), and so you could define an argument that is an object holding a counter:
def myFunction(counter=[0]):
counter[0] += 1
return "aaaabbbb"[counter[0] % 8]
for _ in range(10):
print(myFunction())
This is of course not an exhaustive list of possibilities, but the essence is that programming languages offer their own ways to construct such stateful functions.
Iterators
Some languages offer a different approach: iterators. This means the function produces a stream of return values. The function can run to produce the first value after which the running state is saved until a new value is requested from it. The function's execution context is then restored to run until it can produce the next value, ...etc.
Here is how that design would look in JavaScript:
function * myIterator() {
let callCount = 0;
while (true) {
yield "aaaabbbb"[callCount++ % 8];
// ^^^^^ a language construct for yielding back to the caller
}
}
let iter = myIterator();
for (let i = 0; i < 10; i++) {
console.log(iter.next().value);
}
When a programming language offers this possibility, it is often preferred over the other alternatives listed earlier.

CouchDB null value when sort descending

I have CouchDB view that gives me a correct value in natural order and a null when sorted descending, here are the Futon screenshots:
Natural order
Descending order
Here is the view code:
"informe_precios": {
"map": "function(doc){if(doc.doc_type=='precio'){emit([doc.comprador,doc.fecha.substr(0,4),doc.fecha.substr(5,2)],{precio:doc.precio,litros:doc.litros});}}",
"reduce": "function(keys, values, rereduce){var importe= 0; var totallitros = 0;for(var i = 0; i < values.length; i++) {importe += values[i].precio*values[i].litros;totallitros += values[i].litros;}return importe/totallitros;}"
}
I need it descending because I want to get 12 last values.
TIA
Diego
You're always assuming that your reduce function is called with the output of your map function, ie. you're not handling the rereduce situation.
In the rereduce your values will be the importe/totallitros values from previous reduce calls.
Your reduce function is getting a "price per liter" average for each month, so because it's an average there's no way for your rereduce function to actually handle that data because for the multiple values coming in there's no way to know their weight in the average.
So, you'll need to change your function to return the count so that you can use that to weight the average in the rereduce function (we're also using the inbuilt sum function to make things simpler):
function(keys, values, rereduce) {
if (rereduce) {
var length = sum(values.map(function(v){return v[1]}));
var avg = sum(values.map(function(v){
return v[0] * (v[1] / length)
}));
return [avg, length];
}
else {
var importe= 0;
var totallitros = 0;
for( var i = 0; i < values.length; i++) {
importe += values[i].precio * values[i].litros;
totallitros += values[i].litros;
}
return [ importe/totallitros, values.length ];
}
}
The final result you'll see in your view here will be an array, so you'll always need to pick out the first element of that in your client code.

Slickgrid Filtering without Dataview

Is it possible to filter a Slickgrid without using the DataView?
In case it isn't possible, how should the data array be structured in order to display correctly?
I don't have a working example atm. Thanks
Later edit:
After doing some more homework, a filterable datagrid is all about getting matching indexes in a nested array... to get a live sorted result-set that gets updated with grid.setData(filterData);grid render; one should do the following
function intersect(a, b) // find an intersection of 2 arrays (google result on SO
{
var ai=0, bi=0;
var a = a.sort();
var b = b.sort();
var result = new Array();
while( ai < a.length && bi < b.length )
{
if (a[ai] < b[bi] ){ ai++; }
else if (a[ai] > b[bi] ){ bi++; }
else /* they're equal */
{
result.push(a[ai]);
ai++;
bi++;
}
}
return result;
}
// given results sets are arrays of indexes matching search criteria
a = [1,2,3,4];
b = [2,3,4,5];
c = [3,4,5,6];
d = [4,5,6,7];
// should reunite in a nested array
array = [a,b,c,d];
// check intersections for each array[k] and array[k+1]
k = array[0];
for (var i = 0; i<array.length-1; i++){
k = intersect(k,array[i+1]);
}
console.log(k) // returns 4
// k array is the index array that
// is used to build filterData[i] = data[j]
// depends if id is stored in data or in case
// of a database, it is stored in data
// tested in firebug
// thanks
Filter the underlying data array and call grid.setData(filteredData).

Resources