I have 3 lines of C# Interop code that I am struggling to convert to ClosedXML. Can anyone please help?
str2 = worksheet.Range("B3", "L13").get_End(XlDirection.xlDown).get_Address(false, false, XlReferenceStyle.xlA1, System.Type.Missing, System.Type.Missing).Replace("B", "L");
object[,] objArray = (object[,]) worksheet.Range("B3", str2).Value;
str3 = worksheet.Range("B3", "L13").get_End(XlDirection.xlDown).get_Address(false, false, XlReferenceStyle.xlA1, System.Type.Missing, System.Type.Missing).Replace("B", "L");
Thanks
As answered here
This snipped looks overly complicated. First, you create a range from B3 to L13, then move down to the last row (getting to B13, apparently), then replace B to L which gives you L13 and finally you create a range B3:L13 once more to get the values from there.
ClosedXML does not have a built-in method to convert a range into a two-dimensional array but this can be easily done manually:
var range = worksheet.Range("B3:L13");
var objArray = new object[range.ColumnCount(), range.RowCount()];
for (int i = 0; i < range.ColumnCount(); i++)
{
for (int j = 0; j < range.RowCount(); j++)
{
objArray[i, j] = range.Cell(j+1, i+1).Value;
}
}
Related
I was trying to optimize runtime some code that ran really slowly, when searching it up google came up with this: https://developers.google.com/apps-script/guides/support/best-practices#:~:text=Use%20batch%20operations,-Scripts%20commonly%20need&text=Alternating%20read%20and%20write%20commands,data%20out%20with%20one%20command.
it shows an example of inefficient code:
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
xcoord = xmin;
for (var x = 0; x < 100; x++) {
var c = getColorFromCoordinates(xcoord, ycoord);
cell.offset(y, x).setBackgroundColor(c);
xcoord += xincrement;
}
ycoord -= yincrement;
SpreadsheetApp.flush();
}
and efficient code:
var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColorFromCoordinates(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
I tried to understand how this code works and tried running it but first of all "cell" doesn't seem to get used and I do not understand the code at all. What is a version of the code that actually works and how does this make it more efficient? And what part of this code batches the calls and how can I use this in my own coding?
Basically, what it does it reduce the number of calls by its methods.
The inefficient code above calls offset and setBackgroundColor every loop thus making it resource intensive and time consuming.
For the efficient code, it uses the loop to build the 2d array which then will be used on a single call on the method setBackgroundColors to execute it by bulk.
What takes much of the run time is the method calls, so reducing it would be very beneficial. This would make use of loops to build 2d arrays for the array versions of the methods single execution.
e.g.:
setValue -> setValues
setBackgroundColor -> setBackgroundColors
Pseudocode:
from:
loop {
setValue(x[i][j])
}
to:
loop {
x[i][j] = data
}
setValues(x)
I'm trying to write Array(1, 2) to binary file as bytes.
So output file should contain 00000001 00000010.
I understood that I have to use ADODB.Stream, but I haven't found any solution for such simple task.
var data = new Array(1, 2)
out = WScript.CreateObject("ADODB.Stream")
out.Type = 1
out.Open()
out.Write(data)
out.SaveToFile("output.bin", 2)
out.Close()
Code above gives error:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
Any ideas how to convert data array to acceptable type?
You can use the WriteAll function described here: Reading and Writing Binary Files Using JScript. Copyright: Dr Alexander J Turner.
Please note, the Stream shall be of type text, and then you will need to do the text<->binary conversion.
I just tested all the code and it worked fine for me.
Here is a complete example:
var bf1 = new BinaryFile("C:/Temp/test.bin");
var outBuf = '';
for(var i=0, l=data.length; i<l; i++) {
outBuf += String.fromCharCode(data[i]);
}
bf1.WriteAll(outBuf);
The result looks like this:
EDIT:
I just did a more compact adaptation of the code, to avoid the hex conversion and the double loop:
// Codepage conversion table
var _c=[199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,
201,230,198,244,246,242,251,249,255,214,220,162,163,165,8359,402,
225,237,243,250,241,209,170,186,191,8976,172,189,188,161,171,187,
9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,
9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,
9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,
945,223,915,960,931,963,181,964,934,920,937,948,8734,966,949,8745,
8801,177,8805,8804,8992,8993,247,8776,176,8729,183,8730,8319,178,9632,160],
_w=[],
_r=[];
// Create forward lookup to write & reverse lookup to read
for(var i=0, l=256; i<l; i++) {
var c = (i<128) ? i : _c[i-128];
_w[i] = c;
_r[c] = i;
}
// Read binary data from disk
function binFileToArray(fileName, binArray){
var inStream = new ActiveXObject("ADODB.Stream");
inStream.Type = 2;
inStream.CharSet = '437';
inStream.Open();
inStream.LoadFromFile(fileName);
var inString = inStream.ReadText();
inStream.Close();
for(var i=0, l=inString.length; i<l; i++) {
binArray.push(_r[inString.charCodeAt(i)]);
}
}
// Write binary data to disk
function binArrayToFile(binArray, fileName){
var outStream = new ActiveXObject('ADODB.Stream');
var outString = '';
for(var i=0, l=binArray.length; i<l; i++) {
outString += String.fromCharCode(_w[binArray[i]]);
}
outStream.Type = 2;
outStream.CharSet = '437';
outStream.Open();
outStream.WriteText(outString);
outStream.SaveToFile(fileName, 2);
outStream.Close();
}
// TEST: read binary file from disk & write array back to disk
var testArray = [];
binFileToArray('c:/temp/test.bin', testArray);
binArrayToFile(testArray, 'c:/temp/test2.bin');
// both files equals
I created a level editor for web game, I can build, save, load and play levels.
Now I want to edit some levels but I have a weird situation.
I export a level as a single array, it looks like this 3,4,5,5,7,89,4,2,1...and those numbers represent frames. (tile-based).
Now if I want to edit this level and save it again, I need a level to be described as multidimensional array.
Actually, when I save the level I have a string that describes my map, then I convert string to array.
So can you tell me (if possible), how to convert this array1 (or string) to array2?
Lets say I have only 25 tiles (map from level editor is array1)
array1 =
1,1,1,1,1,
2,2,2,2,2,
3,3,3,3,3,
4,4,4,4,4,
5,5,5,5,5
I need this:
array2 =
[
[1,1,1,1,1],
[2,2,2,2,2],
[3,3,3,3,3],
[4,4,4,4,4],
[5,5,5,5,5]
];
UPDATE:
So I need 2d array to build level container.
I do not have experience with tile based games, but here you can see what I do.
Let's say I have 2d array and this is how I create a new level container:
for (i = 0; i < array2.length; i++)
{
for (var j = 0; j < array2[i].length; j++)
{
tile = new Tile();
tile.name = "" + i + j;
tile.x = j * tile.width;
tile.y = i * tile.height;
levelContainer.addChild(tile);
tile.gotoAndStop(array2[i][j]+1);
tile.addEventListener(MouseEvent.MOUSE_DOWN,
buildingLeve);
}
}
addChild(levelContainer);
I have tried to get 2d array from single array as Rudolfwm and Marcela suggested, but when I want to edit a level container using new array2, my tiles go on wrong frames.
For example, if correct frame is 1, tile goes to frame 11,
This code above (building level) works if I create my own 2d array, but not if I convert string to 2d array as suggested.
Try array1[x+y*row] which gives the same result as copying all your data to array2[x][y].
Or if you insist on 2d arrays:
var array2 = new Array(row);
for (var y = 0; y < row; y++) {
array2 [y] = new Array(column);
for(var x=0; x < column; x++) {
array2 [y][x]=array1[x+y*row];
}
}
You start with a String and convert that into an Array using String.split().
Once you have a temporary array, you use a nested loop to populate the final array (arr21).
var row:int = 5;
var column:int = 5;
var arr1:String = "1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5";
var tempArr:Array = arr1.split(',');
var arr2:Array = [];
for(var i:int = 0; i < row; i++)
{
arr2[i] = []; // create a new row array
for(var j:int = 0; j < column; j++)
{
// grab the first item from the temp array and push it onto the row array
arr2[i].push(tempArr.shift());
}
}
NOTE: This is not optimized, and could become quite laggy with larger level maps. This is just to give you an idea of where you can start.
I have an array like var test:Array = new Array("a", "b", "c"); How can I write a method to get one element and make it be string each time when I call this method. i.e when I call the method, it should return only 'a' and next time return only 'b' and so on.
You can use function shift of Array,here is a link about the function array shift
var test:Array = new Array("a", "b", "c");
var firstLetter:String = test.shift();//"a"
var secondLetter:String = test.shift();//"b"
var thirdLetter:String = test.shift();//"c"
#Pan's answer is correct, but I feel the need to flag the fact that shift() ignites an extremely slow process of re-indexing your entire array. It's not something you need to concern yourself with with small arrays like in your example, but for larger arrays there's a significant performance boost if you reverse() the array first and then use pop(). I'll create a performance comparison below.
Set up our test arrays:
var shiftCopy:Array = [];
var popCopy:Array = [];
for(var i:int = 0; i < 100000; i++)
{
var rand:Number = Math.random() * i;
shiftCopy.push('a' + rand);
popCopy.push('a' + rand);
}
Run the tests:
// Using shift.
var t:int = getTimer();
while(shiftCopy.length > 0) shiftCopy.shift();
trace(getTimer() - t);
// Using reverse and pop.
t = getTimer();
popCopy.reverse();
while(popCopy.length > 0) popCopy.pop();
trace(getTimer() - t);
My results:
shift: 1651ms
pop: 19ms
I'm using MySql and Nodejs. I need to store a huge string made of only 0s and 1s. (This is a map grid. 0 = Can Move, 1 = Can't move.)
Ex: 00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000
...
Should I take that string, encode it into a base64 string and store it that way? Then when I need it, I decode it? If so, how would I do it, using Nodejs/Javascript?
Thanks
The data you're storing appears to compress easily, why don't you use the built-in MySql COMPRESS function
Raw:
mysql> select length('00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000');
332
With COMPRESS
mysql> select length(compress('00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000'));
23
Don't store a string, store binary.
Here's an example of a way you could convert that data to binary. Hopefully you can reengineer things so that your map data is never represented as a string in the first place.
static void Main(string[] args)
{
const string data =
"00000000000000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000";
var arrayLength = data.Length/8;
if (data.Length%8 != 0)
arrayLength++;
var binaryData = new byte[arrayLength];
byte nextByte=0;
var k = -1;
for (var i = 0; i < data.Length; i++)
{
var j = i%8;
if (j == 0)
{
binaryData[++k] = nextByte;
nextByte = 0;
}
var bit = int.Parse(data[i].ToString());
if(bit==1)
nextByte |= (byte)(bit << j);
}
binaryData[k] = nextByte;
}