Is there a "diff" function in Oracle PL/SQL, that shows differences between two text strings? - oracle

We have logging tables in our Oracle database that show old and new values when changes are made to certain data fields. One of these fields is a SQL_TEXT field (for running reports via dynamic SQL).
For example:
CREATE TABLE schema1.rpt_sql_log (
rpt_id NUMBER(9), -- surrogate key of report
chg_id NUMBER(9), -- change number of query for this rpt_id
old_sql_txt VARCHAR2(2000), -- old report SQL statement
new_sql_txt VARCHAR2(2000) -- new report SQL statement
);
INSERT INTO schema1.rpt_sql_log VALUES (
1,
2,
'SELECT emp_id, dept_id, salary FROM emp ORDER BY emp_id',
'SELECT emp_id, dept_nm, salary FROM emp e INNER JOIN dept d ON e.dept_id = d.dept_id ORDER BY emp_id'
);
COMMIT;
Our analyst ordinarily would export these fields to 2 separate text files and then open them in BeyondCompare, UltraCompare, or WinMerge. They have asked if it is possible to do this textual comparison/diff directly in a query (i.e., is there a built-in diff function). To the best of my knowledge, no such built-in function exists.
My question is this: is there already a "diff-like" function available online that mimics the output of a Myers diff algorithm (i.e., something that highlights or <tag>s the changes, as one might see in Git or TortoiseSVN)

To my knowledge, there is no such built-in PL/SQL function to do so.
However, using this JavaScript code which describes a diff function that adds and tags and the MultiLingual Engine capabilities of the 21c Oracle database release (which allows you to create stored procedures that can execute JavaScript code); you could go with such an approach:
set define off
set serveroutput on size unlimited
DECLARE
ctx DBMS_MLE.context_handle_t := DBMS_MLE.create_context();
codeSnippet clob ;
result clob;
BEGIN
codeSnippet := q'~
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
* Modified by Chu Alan "sprite"
*
* Released under the MIT license.
*
* More Info:
* http://ejohn.org/projects/javascript-diff-algorithm/
*/
function escape(s) {
var n = s;
n = n.replace(/&/g, "&");
n = n.replace(/</g, "<");
n = n.replace(/>/g, ">");
n = n.replace(/"/g, """);
return n;
}
function diffString( o, n ) {
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
var str = "";
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = ["\n"];
} else {
oSpace.push("\n");
}
var nSpace = n.match(/\s+/g);
if (nSpace == null) {
nSpace = ["\n"];
} else {
nSpace.push("\n");
}
if (out.n.length == 0) {
for (var i = 0; i < out.o.length; i++) {
str += '<del>' + escape(out.o[i]) + oSpace[i] + "</del>";
}
} else {
if (out.n[0].text == null) {
for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
str += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
}
}
for ( var i = 0; i < out.n.length; i++ ) {
if (out.n[i].text == null) {
str += '<ins>' + escape(out.n[i]) + nSpace[i] + "</ins>";
} else {
var pre = "";
for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
pre += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
}
str += " " + out.n[i].text + nSpace[i] + pre;
}
}
}
return str;
}
function randomColor() {
return "rgb(" + (Math.random() * 100) + "%, " +
(Math.random() * 100) + "%, " +
(Math.random() * 100) + "%)";
}
function diffString2( o, n ) {
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = ["\n"];
} else {
oSpace.push("\n");
}
var nSpace = n.match(/\s+/g);
if (nSpace == null) {
nSpace = ["\n"];
} else {
nSpace.push("\n");
}
var os = "";
var colors = new Array();
for (var i = 0; i < out.o.length; i++) {
colors[i] = randomColor();
if (out.o[i].text != null) {
os += '<span style="background-color: ' +colors[i]+ '">' +
escape(out.o[i].text) + oSpace[i] + "</span>";
} else {
os += "<del>" + escape(out.o[i]) + oSpace[i] + "</del>";
}
}
var ns = "";
for (var i = 0; i < out.n.length; i++) {
if (out.n[i].text != null) {
ns += '<span style="background-color: ' +colors[out.n[i].row]+ '">' +
escape(out.n[i].text) + nSpace[i] + "</span>";
} else {
ns += "<ins>" + escape(out.n[i]) + nSpace[i] + "</ins>";
}
}
return { o : os , n : ns };
}
function diff( o, n ) {
var ns = new Object();
var os = new Object();
for ( var i = 0; i < n.length; i++ ) {
if ( ns[ n[i] ] == null )
ns[ n[i] ] = { rows: new Array(), o: null };
ns[ n[i] ].rows.push( i );
}
for ( var i = 0; i < o.length; i++ ) {
if ( os[ o[i] ] == null )
os[ o[i] ] = { rows: new Array(), n: null };
os[ o[i] ].rows.push( i );
}
for ( var i in ns ) {
if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) {
n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] };
o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] };
}
}
for ( var i = 0; i < n.length - 1; i++ ) {
if ( n[i].text != null && n[i+1].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
n[i+1] == o[ n[i].row + 1 ] ) {
n[i+1] = { text: n[i+1], row: n[i].row + 1 };
o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 };
}
}
for ( var i = n.length - 1; i > 0; i-- ) {
if ( n[i].text != null && n[i-1].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
n[i-1] == o[ n[i].row - 1 ] ) {
n[i-1] = { text: n[i-1], row: n[i].row - 1 };
o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 };
}
}
return { o: o, n: n };
}
var bindings = require("mle-js-bindings");
var string1 = bindings.importValue("string1");
var string2 = bindings.importValue("string2");
bindings.exportValue("result", diffString(string1,string2)); ~';
dbms_mle.export_to_mle(ctx, 'string1', 'The red brown fox jumped over the rolling log.');
dbms_mle.export_to_mle(ctx, 'string2', 'The brown spotted fox leaped over the rolling log');
DBMS_MLE.eval(ctx, 'JAVASCRIPT', codeSnippet);
DBMS_MLE.import_from_mle(ctx, 'result', result);
DBMS_OUTPUT.put_line(result);
DBMS_MLE.drop_context(ctx);
END;
/
Running the code above using SQLcl, gives me:
The <del>red </del> brown <ins>spotted </ins> fox <del>jumped </del><ins>leaped
</ins> over the rolling <del>log.
</del><ins>log
</ins>
PL/SQL procedure successfully completed.
SQL>

Related

AmChart- After updating fieldMappings and dataSet,Graph is not plotting

Problem Statement:
after updating fieldMappings and dataSet during runtime(After clicking on a button) for a stockgraph, validateNow() / validteData() is not plotting the graph.
Note: MACD0 is added from 25th element onward and expoSignalLine0 is added from 33rd element onward in the dataprovider and fieldMapping is also getting updated and can be verified same in console.enter code here
Following is the Code snippet:
(addMACD function is called on click of a button)
function addMACD() {
var chart = AmCharts.charts[ 0 ];
AmCharts.MACDGraphs = 0;
AmCharts.expoSignalLineGraphs = 0;
var MACDField = "MACD"+ AmCharts.MACDGraphs;
var expoSignalLineField = "expoSignalLine"+ AmCharts.expoSignalLineGraphs;
chart.dataSets[0].fieldMappings.push( {
fromField : MACDField,
toField : MACDField
},
{
fromField : expoSignalLineField,
toField : expoSignalLineField
});
var currClose;
var prevClose;
var twelveDayEMA =[];
var twentySixDayEMA =[];
var MACDarray = [];
var signalLineArray = [];
var MACDperiod = 9 ;// 9 day exponential average
for ( var i = 1; i < (chart.dataSets[0].dataProvider.length); i++) {
var dp = chart.dataSets[0].dataProvider[i - 1];
prevClose = parseFloat(dp["close"]);
var dp = chart.dataSets[0].dataProvider[i];
currClose = parseFloat(dp["close"]);
if( i==1){
twelveDayEMA[i] = (0.15*currClose) + (0.85*prevClose);
twentySixDayEMA[i] = (0.075*currClose) + (0.925*prevClose);
}
else{
twelveDayEMA[i] = (0.15*currClose) + (0.85*twelveDayEMA[i - 1]);
twentySixDayEMA[i] = (0.075*currClose) + (0.925*twentySixDayEMA[i - 1]);
}
if(i >= 25){
MACDarray[i] = twelveDayEMA[i] - twentySixDayEMA[i] ;
dp[MACDField] = MACDarray[i];
if(i == 25){
signalLineArray[i] = MACDarray[i];
}
else{
signalLineArray[i] = ( MACDarray[i]*(2/( MACDperiod + 1)) ) + ( signalLineArray[i - 1]*(1-(2/( MACDperiod + 1))) )
}
}
if(i >=33){
dp[expoSignalLineField] = signalLineArray[i];
}
}
console.log(chart);
if ( chart.panels.length == 1 || chart.panels.length == 2 || chart.panels.length == 3 || chart.panels.length == 4 || chart.panels.length == 5) {
var newPanel = new AmCharts.StockPanel();
newPanel.allowTurningOff = true;
newPanel.title = "MACD";
newPanel.showCategoryAxis = false;
graph1 = new AmCharts.StockGraph();
graph1.valueField = MACDField;
graph1.useDataSetColors = false;
graph1.lineColor="#6699FF";
graph1.title = "MACD";
newPanel.stockGraphs.push( graph1 );
graph2 = new AmCharts.StockGraph();
graph2.valueField =expoSignalLineField;
graph2.useDataSetColors = false;
graph2.lineColor = "#990000";
graph2.title = "MACD2";
newPanel.stockGraphs.push( graph2 );
var legend = new AmCharts.StockLegend();
legend.markerType = "none";
legend.markerSize = 0;
newPanel.stockLegend = legend;
chart.addPanelAt( newPanel, 1 );
chart.validateData();
chart.validateNow();
//chart.write("chartdiv");
}
}
You have to call validateNow first, then call validateData.
Alternatively, you can call validateNow(true, false) which has the same effect as calling the two functions separately.
Updated fiddle

Finding path from cell x to cell y in a grid so that all cells are parsed once

I am trying to code an algorithm so that it can start from any "start" cell of a grid ( eg.cell no. 4 in the pic) and parse through each cell of a grid once. The grid can be of any size 3x3, 4x4, 8x8 etc.
The following codes generates such paths. And works fine for many cells in 8x8 grid. But for many cells, it takes forever to search a path.
I was wondering if there is some better solution that can be referenced, so that the solution can be optimized.
package
{
import flash.display.MovieClip;
public class Main extends MovieClip
{
private var rand_Num;
public var node0_Mc:MovieClip ,node1_Mc:MovieClip,node2_Mc:MovieClip,node3_Mc:MovieClip,node4_Mc:MovieClip,node5_Mc:MovieClip,node6_Mc:MovieClip,node7_Mc:MovieClip,node8_Mc:MovieClip,node9_Mc:MovieClip,
node10_Mc:MovieClip,node11_Mc:MovieClip,node12_Mc:MovieClip,node13_Mc:MovieClip,node14_Mc:MovieClip,node15_Mc:MovieClip,node16_Mc:MovieClip,node17_Mc:MovieClip,node18_Mc:MovieClip,node19_Mc:MovieClip,
node20_Mc:MovieClip,node21_Mc:MovieClip,node22_Mc:MovieClip,node23_Mc:MovieClip,node24_Mc:MovieClip,node25_Mc:MovieClip,node26_Mc:MovieClip,node27_Mc:MovieClip,node28_Mc:MovieClip,node29_Mc:MovieClip,
node30_Mc:MovieClip,node31_Mc:MovieClip,node32_Mc:MovieClip,node33_Mc:MovieClip,node34_Mc:MovieClip,node35_Mc:MovieClip,node36_Mc:MovieClip,node37_Mc:MovieClip,node38_Mc:MovieClip,node39_Mc:MovieClip,
node40_Mc:MovieClip,node41_Mc:MovieClip,node42_Mc:MovieClip,node43_Mc:MovieClip,node44_Mc:MovieClip,node45_Mc:MovieClip,node46_Mc:MovieClip,node47_Mc:MovieClip,node48_Mc:MovieClip,node49_Mc:MovieClip,
node50_Mc:MovieClip,node51_Mc:MovieClip,node52_Mc:MovieClip,node53_Mc:MovieClip,node54_Mc:MovieClip,node55_Mc:MovieClip,node56_Mc:MovieClip,node57_Mc:MovieClip,node58_Mc:MovieClip,node59_Mc:MovieClip,
node60_Mc:MovieClip, node61_Mc:MovieClip, node62_Mc:MovieClip, node63_Mc:MovieClip;
public const NUM_COLS:Number = 8;
// 3 ;// 4 ;
public const NUM_ROWS:Number = 8;// 3 ;// 4 ;
var chain_Arr:Array = [];
var blockIndex_Arr:Array = [];
var nodearr:Array;
var adjacentNodeArray_Arr:Array = [];
var parsedNodeIndex_Arr:Array = [];
var validNextAdjacentNodeIndexArray_Arr:Array = [];
var validPreviousAdjacentNodeIndexArray_Arr:Array = [];
var savePair_Arr:Array = [];
var countChain_Num:Number = 0;
var saveParent_Arr:Array = [];
public function Main()
{
// constructor code
nodearr = [node0_Mc,node1_Mc,node2_Mc,node3_Mc,node4_Mc,node5_Mc,node6_Mc,node7_Mc,node8_Mc,node9_Mc,node10_Mc,node11_Mc,node12_Mc,node13_Mc,node14_Mc,node15_Mc,node16_Mc,node17_Mc,node18_Mc,node19_Mc,node20_Mc,node21_Mc,node22_Mc,node23_Mc,node24_Mc,node25_Mc,node26_Mc,node27_Mc,node28_Mc,node29_Mc,node30_Mc,node31_Mc,node32_Mc,node33_Mc,node34_Mc,node35_Mc,node36_Mc,node37_Mc,node38_Mc,node39_Mc,node40_Mc,node41_Mc,node42_Mc,node43_Mc,node44_Mc,node45_Mc,node46_Mc,node47_Mc,node48_Mc,node49_Mc,node50_Mc,node51_Mc,node52_Mc,node53_Mc,node54_Mc,node55_Mc,node56_Mc,node57_Mc,node58_Mc,node59_Mc,node60_Mc,node61_Mc,node62_Mc,node63_Mc];
var possibleAdjacentNodeIndex_Arr:Array = [];
initValidNextAdjacentNodeIndexArray();
initValidPreviousAdjacentNodeIndexArray();
savePair_Arr = [];
var startIndex_num:Number = 45;// 0 ;
rand_Num = 62;// randomRange(10, (NUM_COLS * NUM_ROWS) - 1);
getAllChainsFromParamNodeIndexParamParentChain(startIndex_num,[startIndex_num]);
}
function initValidNextAdjacentNodeIndexArray():void
{
for (var index_num = 0; index_num < NUM_COLS*NUM_ROWS; index_num++)
{
validNextAdjacentNodeIndexArray_Arr[index_num] = getValidNodeIndexArrayAdjacentToParamNodeIndex(index_num);
//trace(validNextAdjacentNodeIndexArray_Arr[index_num]);
}
}
function initValidPreviousAdjacentNodeIndexArray():void
{
for (var index_num = 0; index_num < NUM_COLS*NUM_ROWS; index_num++)
{
validPreviousAdjacentNodeIndexArray_Arr[index_num] = getValidNodeIndexArrayAdjacentToParamNodeIndex(index_num);
//trace(validNextAdjacentNodeIndexArray_Arr[index_num]);
}
}
//function getAllChainsFromParamNodeIndexParamParentChain( path_arr:Array,index_param_num:Number ):void
function getAllChainsFromParamNodeIndexParamParentChain( index_param_num:Number, parent_arr:Array ):void
{
var i;
if ( countChain_Num > 15 )
{
return;
}
reinitPath();
var adjacent_arr = getValidNodeIndexArrayAdjacentToParamNodeIndex(index_param_num);
for (i = 0; i < adjacent_arr.length; i++)
{
reinitPath();
if ( ( checkRepeat(chain_Arr)) )
{
continue;
}
chain_Arr.push(adjacent_arr[i]);
//trace("chain starts from", chain_Arr);
var nodeIndex_num:Number = adjacent_arr[i];
var nodeIndexExist_num = 0;
var parentNode_num:Number = parent_arr[parent_arr.length - 1];
var bool:Boolean;
while ( isNaN(nodeIndex_num) == false)
{
//var childNodeIndex_num = manageValidAdjacentIndexArray(parent_arr[parent_arr.length-1], parentNode_num , nodeIndex_num );
var childNodeIndex_num = manageValidAdjacentIndexArray(adjacent_arr[i],parentNode_num,nodeIndex_num);
//var childNodeIndex_num = manageValidAdjacentIndexArray(parentNode_num, parentNode_num , nodeIndex_num );
parentNode_num = nodeIndex_num;
nodeIndex_num = childNodeIndex_num;
if ( ( checkRepeat(chain_Arr)) )
{
break;
}
if ( isNaN(nodeIndex_num) == false)
{
chain_Arr.push(nodeIndex_num);
}
}
if (chain_Arr.length > NUM_COLS * NUM_ROWS - 1)
{
//if ( !( checkRepeat(chain_Arr)) )
{
trace(chain_Arr);
saveParent_Arr[saveParent_Arr.length ] = new Array();
for (var k = 0; k < rand_Num; k++)
{
saveParent_Arr[saveParent_Arr.length - 1].push( chain_Arr[k]);
}
countChain_Num++;
}
}
};
for (i = 0; i < adjacent_arr.length; i++)
{
var arr2:Array = parent_arr.slice();
arr2.push(adjacent_arr[i]);
getAllChainsFromParamNodeIndexParamParentChain( adjacent_arr[i], arr2 );
}
function reinitPath():void
{
chain_Arr = [];
chain_Arr = chain_Arr.concat(parent_arr);
}
}
private function checkRepeat(chain_arr:Array):Boolean
{
var bool:Boolean;
var num = rand_Num;
if (chain_arr.length >= num - 1)
{
for (var i = 0; i < saveParent_Arr.length; i++)
{
//trace( saveParent_Arr[i][0], saveParent_Arr[i][1]);
if (saveParent_Arr[i] != undefined)
{
var z = 0;
for (var j = 0; j < num; j++)
{
if (saveParent_Arr[i][j] == chain_arr[j])
{
z++;
if ( z >= num)
{
bool = true;
break;
}
}
else
{
break;
}
}
if (bool)
{
break;
}
}
}
}
return bool;
}
function randomRange( minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
function randomizeArray(arr:Array ):void
{
for (var i = 0; i < arr.length; i++)
{
var random = randomRange(0,arr.length - 1);
var temp = arr[i];
arr[i] = arr[random];
arr[random] = temp;
}
}
//will send NaN if no valid adjacent index array is possible
private function manageValidAdjacentIndexArray(chainStartIndex_num:Number, parentNodeIndex_param_num:Number, nodeIndex_num:Number):Number
{
var num_nan:Number;
var ret_num:Number;
var j;
//var tot:Number = validNextAdjacentNodeIndexArray_Arr[nodeIndex_num].length ;
j = 0;
var arr:Array = validNextAdjacentNodeIndexArray_Arr[nodeIndex_num];// getValidNodeIndexArrayAdjacentToParamNodeIndex(nodeIndex_num) ;
randomizeArray(arr);
while (arr.length > 0 )// && isNaN(ret_num))
{
ret_num = arr[j];//validNextAdjacentNodeIndexArray_Arr[nodeIndex_num][j] ;
//if this index is present in chain then remove it off
if (chain_Arr.indexOf(ret_num) >= 0)
{
//j++ ;
ret_num = num_nan;
}
j++;
if ( j >= arr.length )
{
ret_num = num_nan;
break;
}
}
return ret_num;
}
private function getValidAdjacentIndexToParamNodeIndex(nodeIndex_param_num:Number):Number
{
var adjacentNode_arr:Array = [];
var adjacentRow_arr:Array = [];
var adjacentCol_arr:Array = [];
var allIndex_arr:Array = [];
var r:Number;
var c:Number;
var row_num:Number = int(nodeIndex_param_num / NUM_COLS);
var col_num:Number = (nodeIndex_param_num % NUM_COLS);
allIndex_arr = getAllAdjacentNodeIndexArray(row_num,col_num);
validateIndices(allIndex_arr);
var ret_num:Number;
ret_num = allIndex_arr[0];
return ret_num;
}
function getValidNodeIndexArrayAdjacentToParamNodeIndex(nodeIndex_param_num:Number ):Array
{
var adjacentNode_arr = [];
for (var positionId_num = 0; positionId_num < 8; positionId_num++)
{
var num:Number = getNodeIndexAtParamPositionIdOfParamIndex(positionId_num,nodeIndex_param_num);
if (isNaN(num))
{
}
else
{
adjacentNode_arr.push(num);
}
}
return adjacentNode_arr;
}
private function getAllAdjacentNodeIndexArray(row_num:Number, col_num:Number,within_arr:Array=null):Array
{
var num:Number;
var index_arr:Array = [num,num,num,num,num,num,num,num];
var r:Number;
var c:Number;
if ( row_num > 0 )
{
r = row_num - 1;
c = col_num;
index_arr[0] = r * NUM_COLS + c;
}
if ( col_num < NUM_COLS-1)
{
r = row_num;
c = col_num + 1;
index_arr[1] = r * NUM_COLS + c;
}
if ( row_num < NUM_ROWS-1)
{
r = row_num + 1;
c = col_num;
index_arr[2] = r * NUM_COLS + c;
}
if ( col_num > 0 )
{
r = row_num;
c = col_num - 1;
index_arr[3] = r * NUM_COLS + c;
}
///////////////////////////////////////////
if ( row_num > 0 && col_num > 0)
{
r = row_num - 1;
c = col_num - 1;
index_arr[4] = r * NUM_COLS + c;
}
if ( row_num > 0 && col_num < NUM_COLS-1)
{
r = row_num - 1;
c = col_num + 1;
index_arr[5] = r * NUM_COLS + c;
}
if ( row_num < NUM_ROWS-1 && col_num < NUM_COLS-1)
{
r = row_num + 1;
c = col_num + 1;
index_arr[6] = r * NUM_COLS + c;
}
if ( row_num < NUM_ROWS-1 && col_num > 0 )
{
r = row_num + 1;
c = col_num - 1;
index_arr[7] = r * NUM_COLS + c;
}
return index_arr;
}
//the adjacent node must be present in within_arr, which we splice, one time for variation
function getNodeIndexAtParamPositionIdOfParamIndex( n:Number , nodeIndex_param_num:Number):Number
{
var adjacentNode_arr:Array = [];
var adjacentRow_arr:Array = [];
var adjacentCol_arr:Array = [];
var index_arr:Array = [];
var r:Number;
var c:Number;
var index_num:Number;
var row_num:Number = int(nodeIndex_param_num / NUM_COLS);
var col_num:Number = (nodeIndex_param_num % NUM_COLS);
index_arr = getAllAdjacentNodeIndexArray(row_num,col_num);
validateIndices(index_arr);
var ret_num:Number;
ret_num = index_arr[n];
return ret_num;
}
private function validateIndices(index_arr:Array):void
{
for (var i = 0; i < index_arr.length; i++)
{
if (chain_Arr.indexOf(index_arr[i]) == -1)
{
}
else
{
var num:Number;
index_arr[i] = num;//pushing NaN
}
}
}
}
}
It's a Hamiltonian path problem. It's NP complete and afaik there is still no efficient solution.
check this out: hamilton paths in grid graphs (pdf)
short randomized algorithm explanation: Princeton Hamiltonian path problem
or wikipedia: Hamiltonian path problem
edit:
I did some more research and for your special case of strongly connected square grids (nxn chessboards) a variation of the warndoffs rule for finding a knights tour might give you a solution in near linear time. See here: A method for finding hamiltonian paths and knight tours (pdf)

sorting showing unexpected results

I am sorting a grid with knockout.js. Following is my sort function
this.sortByName = function() {
var event = arguments[1];
var targeElement = event.originalTarget;
// console.info(targeElement);
console.log(targeElement.attributes[1].nodeValue);
order = 'sorting';
configuration.data.sort(function(a, b) {
if(a.name<b.name){
order = 'sorting_desc';
return a.name > b.name ? -1 : 1;
}
else if(a.name>b.name){
order = 'sorting_asc'
return a.name < b.name ? -1 : 1;
}
});
$(targeElement).removeClass('sorting_asc sorting_desc').addClass(order);
};
The by default grid view
The Sorted image 1
The sorted image 2
As you can see the order of sorting is not correct. I have been playing around for 3 days in this issue.
Well I found a solution to this problem
this.sortByName = function() {
currentOrder = arguments[0].sortClass();
var sortColumn = arguments[0].rowText;
if(currentOrder =='sorting' || currentOrder =='sorting_desc'){
currentOrder='sorting_asc';
configuration.data.sort(function(a, b) {
if (a[sortColumn] == b[sortColumn])
return 0;
else if (a[sortColumn] < b[sortColumn])
return -1;
else
return 1;
});
}else{
currentOrder='sorting_desc';
configuration.data.sort(function(a, b) {
if (a[sortColumn] == b[sortColumn])
return 0;
else if (a[sortColumn] > b[sortColumn])
return -1;
else
return 1;
});
}
self.resetSortColumns();
arguments[0].sortClass(currentOrder);
};

Flash create comma from number performance

I wrote a small function that splits a number to commas but I have to run over the number too many times. Can you sugest me a better way to do this?
public static function getCommaString(value:Number):String {
var stringValue:String = value.toString();
if (stringValue.length <= 3) {
return stringValue;
}
var i:int = stringValue.length % 3;
if (i == 0) {
i = 3;
}
for (; i < stringValue.length; i += 4 ) {
var part1:String = stringValue.substr(0, i);
var part2:String = stringValue.substr(i, stringValue.length);
stringValue = part1.concat(",", part2);
}
return stringValue;
}
I put together a testing class that compares your solution and others, including a solution from this blog post and solutions from this related StackExchange question and formatted them in a consistent way for easy comparison:
package
{
public class CommaNumberSolutions
{
public static function commaify( input:Number ):String
{
var split:Array = input.toString().split( '.' ),
front:String = split[0],
back:String = ( split.length > 1 ) ? "." + split[1] : null,
n:int = input < 0 ? 2 : 1,
commas:int = Math.floor( (front.length - n) / 3 ),
i:int = 1;
for ( ; i <= commas; i++ )
{
n = front.length - (3 * i + i - 1);
front = front.slice( 0, n ) + "," + front.slice( n );
}
if ( back )
return front + back;
else
return front;
}
public static function getCommaString( input:Number ):String
{
var s:String = input.toString();
if ( s.length <= 3 )
return s;
var i:int = s.length % 3;
if ( i == 0 )
i = 3;
for ( ; i < s.length; i += 4 )
{
var part1:String = s.substr(0, i);
var part2:String = s.substr(i, s.length);
s = part1.concat(",", part2);
}
return s;
}
public static function formatNumber( input:Number ):String
{
var s:String = input.toString()
var result:String = ''
while ( s.length > 3 )
{
var chunk:String = s.substr(-3)
s = s.substr(0, s.length - 3)
result = ',' + chunk + result
}
if ( s.length > 0 )
result = s + result
return result
}
public static function commaCoder( input:Number ):String
{
var s:String = "";
var len:Number = input.toString().length;
for ( var i:int = 0; i < len; i++ )
{
if ( (len-i) % 3 == 0 && i != 0)
s += ",";
s += input.toString().charAt(i);
}
return s;
}
public static function regex1( input:Number ):String
{
return input.toString().replace( /-{0,1}(\d)(?=(\d\d\d)+$)/g, "$1," );
}
public static function regex2( input:Number ):String
{
return input.toString().replace( /-{0,1}\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,")
}
public static function addCommas( input:Number ):String
{
var negative:String = "";
if ( input < 0 )
{
negative = "-";
input = Math.abs(input);
}
var s:String = input.toString();
var results:Array = s.split(/\./);
s = results[0];
if ( s.length > 3 )
{
var mod:Number = s.length % 3;
var output:String = s.substr(0, mod);
for ( var i:Number = mod; i < s.length; i += 3 )
{
output += ((mod == 0 && i == 0) ? "" : ",") + s.substr(i, 3);
}
if ( results.length > 1 )
{
if ( results[1].length == 1 )
return negative + output + "." + results[1] + "0";
else
return negative + output + "." + results[1];
}
else
return negative + output;
}
if ( results.length > 1 )
{
if ( results[1].length == 1 )
return negative + s + "." + results[1] + "0";
else
return negative + s + "." + results[1];
}
else
return negative + s;
}
}
}
You can see a more detailed analysis at my other answer but you can compare the compactness of each solution and weigh that against their accuracy and performance, however for the sake of brevity this solution is the most accurate and performant (though not the most compact):
public function commaify( input:Number ):String
{
var split:Array = input.toString().split( '.' ),
front:String = split[0],
back:String = ( split.length > 1 ) ? "." + split[1] : null,
n:int = input < 0 ? 2 : 1,
commas:int = Math.floor( (front.length - n) / 3 ),
i:int = 1;
for ( ; i <= commas; i++ )
{
n = front.length - (3 * i + i - 1);
front = front.slice( 0, n ) + "," + front.slice( n );
}
if ( back )
return front + back;
else
return front;
}

Turn Jquery function into pluggin

I recently received some excellent advice for writing some jquery functionality. I am trying to turn it into a pluggin.
this is the code that I got from stackOverflow#micha at this link
https://stackoverflow.com/a/8820946/729820
$('#DischargeDateTimeMask').keypress(function (e) {
var regex = ["[0-1]",
"[0-2]",
":",
"[0-5]",
"[0-9]",
"(\\s)",
"(A|P)",
"M"],
string = $(this).val() + keyboard(e),
b = true;
for (var i = 0; i < string.length; i++) {
if (!new RegExp("^" + regex[i] + "$").test(string[i])) {
b = false;
}
}
return b;
});
function keyboard(a) { var b = a.charCode ? a.charCode : a.keyCode ? a.keyCode : 0; if (b == 8 || b == 9 || b == 13 || b == 35 || b == 36 || b == 37 || b == 39 || b == 46) { if ($.browser.mozilla) { if (a.charCode == 0 && a.keyCode == b) { return true } } } return String.fromCharCode(b) }
I personally attempt to turn it into a pluggin like so...
(function ($) {
$.fn.simpleTimeMask = function () {
$(this).keypress(function (e) {
debugger;
var regex = ["[0-2]",
"[0-4]",
":",
"[0-6]",
"[0-9]",
"(A|P)",
"M"],
string = $(this).val() + keyboard(e),
b = true;
for (var i = 0; i < string.length; i++) {
if (!new RegExp("^" + regex[i] + "$").test(string[i])) {
b = false;
}
}
return b;
});
}
(function ($) {
var methods = {
keyboard: function (a) {
//THIS
var b = a.charCode ? a.charCode : a.keyCode ? a.keyCode : 0; if (b == 8 || b == 9 || b == 13 || b == 35 || b == 36 || b == 37 || b == 39 || b == 46) { if ($.browser.mozilla) { if (a.charCode == 0 && a.keyCode == b) { return true } } } return String.fromCharCode(b)
}
}
});
function keyboard(a) { var b = a.charCode ? a.charCode : a.keyCode ? a.keyCode : 0; if (b == 8 || b == 9 || b == 13 || b == 35 || b == 36 || b == 37 || b == 39 || b == 46) { if ($.browser.mozilla) { if (a.charCode == 0 && a.keyCode == b) { return true } } } return String.fromCharCode(b) }
})(jQuery);
Notice how I have two functions that attempt to do the same thing. One I think would be a function that would be called by a user of this pluggin, the other would be used internally. Anyway, I got this thing all compiled and I attempted to add it to my project, but as expected, it did not work. What would be your recommendations for building this pluggin?

Resources