I am trying to implement a logging mechanism in my code. I have read in some forums that in AS2, string concatenation does not happen at compile time, instead it happens at runtime.
I wanted to know which of the following codes is more optimal:
for (var i:Number = 0; i < n; i++ )
{
var strToReplace:String = "{" + i + "}";
}
or,
for (var i:Number = 0; i < n; i++ )
{
var strToReplace:String = "{%s}".split("%s").join(String(i));
}
Your help would be greatly appreciated as I am a newbie as far as AS2 is concerned. Thank you.
Here is an easy way to test :
var n:Number = 100000;
var beforeTime:Number = getTimer();
for (var i:Number = 0; i < n; i++ ) {
var strToReplace:String = "{" + i + "}";
}
var betweenTime:Number = getTimer();
trace("between : " + (betweenTime - beforeTime));
for (var i:Number = 0; i < n; i++ ) {
var strToReplace:String = "{%s}".split("%s").join(String(i));
}
var afterTime:Number = getTimer();
trace("after : " + (afterTime - betweenTime));
What I get in the traces :
between : 269
after : 866
The first way is 3 times faster : split and join methods have to search inside your string to execute.
If your string is bigger, the difference is even bigger : the first methode duration doesn't change... The second one takes even more time.
You should try.
Related
Hi i have a list of values each value representing the output of a shift of packaging. I want to calculate the average output of 8 weeks. So each time a shift passes the average output changes. My idea is to trigger a function after each shift, which calculates the output. Now theres my problem, how do i get a varible (the one representing the row of the first value) to increase after each trigger of the function? What i tried is to declare the variable before the function and increase the variable of 1 inside the function. Buf ofc the starting value doesnt change this way.. Probably there is an easy way for this i just dont know yet (programming newbie here :)).
let i = 7;
let j = 126;
function schnitt() {
var summe = 0;
var counter = 0;
i++;
j++;
while(i <= j){
var aktuell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(i,6,1,1).getValue();
if(aktuell != ""){
summe = summe + aktuell;
counter++;
i++;
}
else{
i++
}
}
var durchschnitt = summe / counter;
var ausgabe = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(8,7,1,1).setValue(durchschnitt);
}
I have found a work around. I just put var i and j into cells and do it like this:
function schnitt() {
var i = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(3,14,1,1).getValue();
var j = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(4,14,1,1).getValue();
var summe = 0;
var counter = 0;
while(i <= j){
var aktuell = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(i,6,1,1).getValue();
if(aktuell != ""){
summe = summe + aktuell;
counter++;
i++;
}
else{
i++
}
}
var durchschnitt = summe / counter;
var ausgabe = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(8,7,1,1).setValue(durchschnitt);
i = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(3,14,1,1).getValue();
i++;
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(3,14,1,1).setValue(i);
j = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(4,14,1,1).getValue();
j++;
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Auswertung").getRange(4,14,1,1).setValue(j);
}
I need to run a solve three times. Every time solve needs to have different input from different columns of a tuple. That is why I need to access the loop variable with in the OPL as a parameter and need to change that parameter with every loop. Please suggest how to do that in ODM OPL.
(I am able to do it when running a standalone model with a physical .dat file by introducing a int in dat file and changing its values with each loop, but same is not possible when running through an ODM application).
You can do this using a scripting main() function:
.dat file:
param = 0; // This value is actually never used
.mod file:
tuple T {
int round1;
int round2;
}
T t = <1, 2>;
int param = ...;
dvar float x;
minimize x;
subject to { x >= param; }
main {
thisOplModel.generate();
var def = thisOplModel.modelDefinition;
var data = thisOplModel.dataElements;
for (var i = 0; i < 2; ++i) {
if (i == 0)
data.param = thisOplModel.t.round1;
else
data.param = thisOplModel.t.round2;
var opl = new IloOplModel(def, cplex);
opl.addDataSource(data);
opl.generate();
cplex.solve();
writeln("Round " + i + ": " + cplex.getObjValue() + ", " + data.param);
opl.end();
}
}
The scripting code modifies the data before creating a new model in each iteration. You have a more elaborate version of code like this in the cutstock_main.mod example that ships with CPLEX.
What Daniel wrote works fine. If you do not want to have the non necessary .dat file you could write
sub.mod
tuple T {
int round1;
int round2;
}
T t = <1, 2>;
int param = ...;
dvar float x;
minimize x;
subject to { x >= param; }
and then in another model that will be the main one:
tuple T {
int round1;
int round2;
}
T t = <1, 2>;
main {
thisOplModel.generate();
var src = new IloOplModelSource("sub.mod");
var def=new IloOplModelDefinition(src);
var data = new IloOplDataElements();;
for (var i = 0; i < 2; ++i) {
if (i == 0)
data.param = thisOplModel.t.round1;
else
data.param = thisOplModel.t.round2;
var opl = new IloOplModel(def, cplex);
opl.addDataSource(data);
opl.generate();
cplex.solve();
writeln("Round " + i + ": " + cplex.getObjValue() + ", " + data.param);
opl.end();
}
}
which will give
Round 0: 1, 1
Round 1: 2, 2
and
tuple T {
int round1;
int round2;
}
T t = <1, 2>;
int solutions[0..1];
main {
thisOplModel.generate();
var src = new IloOplModelSource("sub.mod");
var def=new IloOplModelDefinition(src);
var data = new IloOplDataElements();;
for (var i = 0; i < 2; ++i) {
if (i == 0)
data.param = thisOplModel.t.round1;
else
data.param = thisOplModel.t.round2;
var opl = new IloOplModel(def, cplex);
opl.addDataSource(data);
opl.generate();
cplex.solve();
writeln("Round " + i + ": " + cplex.getObjValue() + ", " + data.param);
thisOplModel.solutions[i]=opl.x.solutionValue;
opl.end();
}
writeln(thisOplModel.solutions);
}
to address your next question about populating tables
which gives
Round 0: 1, 1
Round 1: 2, 2
[1 2]
I'm trying to loop over the Photoshop preferences. This should be as straightforwards as
for (i = 0; i < app.preferences.length; i++)
{
alert(app.preferences[i]);
}
only the object app.preferences doesn't have a length and accessing each item such as
alert(app.preferences.beepWhenDone); //bool
works, but is tedious and is also possibly version dependent. I know most of them are read-only, but I'm quite keen to list them all.
This should do what you want:
alert(app.preferences.reflect.properties.sort().join("\r"));
Or actually, to also let you inspect the actual values, you could do something like this:
var prefsObject = app.preferences;
var prefs = app.preferences.reflect.properties.sort();
var prefString = "Photoshop Preferences\r";
for(var i = 0; i < prefs.length; i++) {
try {
prefString += prefs[i] + ": " + prefsObject[prefs[i]] + "\r";
} catch (e) {
prefString += prefs[i] + ": " + e.message + "\r";
}
}
alert(prefString);
Can anyone help me understand why this below would not remove named cals. It seems to work fine until the very last line where it does the save. I don't get any exceptions or error messages.
When i look in QV Management console under System>Licenses i still see the ones that were supposed to be removed (Named user CALs)
Client Build Number: 11.20.13314.0
QMSClient Client;
string QMS = "http://localhost:4799/QMS/Service";
Client = new QMSClient("BasicHttpBinding_IQMS", QMS);
string key = Client.GetTimeLimitedServiceKey();
ServiceKeyClientMessageInspector.ServiceKey = key;
List<ServiceInfo> MyQVS = Client.GetServices(ServiceTypes.QlikViewServer);
Client.ClearQVSCache(QVSCacheObjects.All);
CALConfiguration myCALs = Client.GetCALConfiguration(MyQVS[0].ID, CALConfigurationScope.NamedCALs);
List<AssignedNamedCAL> currentNamedCALs = myCALs.NamedCALs.AssignedCALs.ToList();
List<int> indexToRemove = new List<int>();
int cnt = 1;
for (int i = 0; i < currentNamedCALs.Count; i++)
{
if ((currentNamedCALs[i].QuarantinedUntil < System.DateTime.Now)
&& (currentNamedCALs[i].LastUsed < DateTime.Now.AddDays(daysFromToday)))
{
Console.WriteLine("[" + cnt + "] " + currentNamedCALs[i].UserName +
"; Last used: " + currentNamedCALs[i].LastUsed);
indexToRemove.Add(i);
cnt++;
}
}
Console.WriteLine();
for (int i = indexToRemove.Count; i > 0; i--)
{
if (currentNamedCALs[indexToRemove[i - 1]] != null)
{
currentNamedCALs.RemoveAt(indexToRemove[i - 1]);
}
}
Console.WriteLine("\nDone");
myCALs.NamedCALs.AssignedCALs = currentNamedCALs;
Client.SaveCALConfiguration(myCALs);
I was helped earlier in creating this code that would create a histogram of a randomint. Everything looks good except I accidently had the output as a sum instead of a mean of all the numbers that were randomly chosen.I dont want to mess anything up so I was just going to ask, How can I convert this sum into a mean output instead?
import java.util.Random;
class Assignment4
{
public static void main(String[] args)
{
Random r = new Random();
int sum = 0;
int[] bins = new int[10];
for(int i = 0; i < 100; i++)
{
int randomint = 1 + r.nextInt(10);
sum += randomint;
bins[randomint-1]++;
//System.out.print(randomint + ", ");
}
System.out.println("Sum = " + sum);
System.out.println("Data shown below: ");
for (int i = 0; i < bins.length; i++)
{
int binvalue = bins[i];
System.out.print((i+1) + ": ");
for(int j = 0; j < binvalue; j++)
{
System.out.print('*');
}
System.out.println(" (" + binvalue + ")");
}
}
}
Never mind figured it out.... just turned System.out.println("Sum = " + sum); into System.out.println("Mean = " + sum/100);