I have a directed graph where paths are stored in JSON array like. It is in the form of source and destination .
Var pathDirection = [{"Source":2,"Destination":3},
{"Source":3,"Destination":4},
{"Source":5,"Destination":4},
{"Source":2,"Destination":5},
{"Source":4,"Destination":6}];
Using above it forms graph like below structure .
My problem is I don’t know the starting point and I have to find all possible path to reach 6 from any node
Like for above graph different path to reach 6 is
Output:
[4 ->6]
[3->4 ->6]
[5->4 ->6]
[2->5->4 ->6]
[2->3->4 ->6]
I have tried to write below algo using backtracking which is working fine but looking for some best algo to find. Please suggest any other possible way to do same and how can i optimize below programe.
// BackTrack From End Node Destination 6
var getAllSource = function(destId){
var sourceForsameDist = [];
pathDirection.forEach(function(eachDirection){
if(eachDirection.Destination == destId){
sourceForsameDist.push(eachDirection.Source);
}
});
return sourceForsameDist;
};
var diffPath = [];
var init = function(destination){
var sourceId = getAllSource(destination[destination.length - 1]);
if(sourceId.length === 0){
diffPath.push(destination);
}
for(var i=0;i<sourceId.length;i++){
var copy = destination.slice(0);
copy.push(sourceId[i]);
init(copy);
}
};
init([6]);
console.log(diffPath); // [[6,4,3,2],[6,4,5,2]]
I have tried to do using backtracking which is working fine but looking for some best algo to find.
I'd call it Depth-First-Search instead of backtracking, but yes the algorithm is fine.
However, I'd have some suggestions on the implementation:
make diffPath a local variable and return it from the init function
If you omit the if(sourceId.length === 0) condition then you will get the expected output, not only the the paths from the sources
instead of looping through the whole pathDirections in your getAllSource function, I'd use a lookup table that is filled before starting the traversal
rename init to something more meaningful
Related
I currently have a findFile function I use within a forEach Loop to iterate through an array of filenames and then provide a new array of the file system paths for each of the filenames within the original array:
var dir = 'Some File System Path';
const fs = require('fs');
const findFile = function (dir, pattern) {
var results = [];
fs.readdirSync(dir).forEach(function (dirInner) {
dirInner = path.resolve(dir, dirInner);
var stat = fs.statSync(dirInner);
if (stat.isDirectory()) {
results = results.concat(findFile(dirInner, pattern));
}
if (stat.isFile() && dirInner.endsWith(pattern)) {
results.push(dirInner);
}
});
return results;
};
var newFileArr = ['1.txt', 'file2.txt', 'file3.txt', 'file4.txt']
function fpArr(newFileArr) {
const fpArray = [];
newFileArr.forEach((file => {
fpArray.push(findFile(dir, file).toString())
//console.log(fpArray)
}));
OutPut:
[
/some/file/path/file1.txt,
/some/file/path/1.txt,
/some/file/path/file2.txt,
/some/file/path/file3.txt,
/some/file/path/file4.txt
]
The issue I am facing is my findFile looks for a pattern match and it picks up the path for "1.txt" presumably when it is searching for "file1.txt". I know this is an edge case, but it is an important edge case because other filenames may end with the same letters or numbers and I do not want those to be picked up in the file path array output. I have tried several ideas such as ".match()" and ".startsWith" however those will only work with a string literal or regEx as far as I can tell which causes the search itself to fail. I am looking to see if there is a way to get the findFile function to do an exact match based off a variable of some string value? Any help getting me in the right direction is appreciated.
[
'K_01.00.0000.iar',
'HELLOWORLDKLA_01.00.0000.iar',
'HELLO_KLA_01.00.0000.iar',
'KLA_01.22.7895.iar',
'KLA_HELLO_WORLD_2_01.00.0000.iar',
'KLA_02_WORLD_01.00.0000.iar'
]
[]
Above are the actual 2 arrays I am working with. The first array is just a simply array of filenames. The bottom array has been run through both sync and you async/await solution. For some reason even with the RegExp added it still picks up 2 files which are not listed in the filename array. I added the file paths to show none of the files are in the root directory and I spread out the files into sub directories to ensure the recursive search is working. I will keep messing with it to see if I can figure out why the RegExp solution is bringing these files into the array when they shouldn't be....
I'm afraid I don't have enough reputation to comment so am posting an answer!
Your code seems to work and if I understand rightly that you want to find all files from a list against a directory and sub directories giving you the paths to these files. Is that correct?
When I ran your code it does indeed pick up the four files in newFileArr and excludes the 1.txt, I've created a codesandbox demo to show you with dummy files.
I've also taken the liberty to create a codesandbox that demonstrates how to do this in a single function using RegExp and map to create dynamic regex expressions if that is useful.
I'm trying to develop a javascript code using opencv.js, I have python code with the same requirement, I converted many lines but some are very hard to find, please guide me.
last 3 lines from python code unable to find for javascript opencv.js.
def find_marker(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 35, 125)
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts) //these three line are unable to find for javascript.
c = max(cnts, key = cv2.contourArea)
return cv2.minAreaRect(c)
In the first line, the code is using the function in imutils python package. If you see the grab_contours method in imutils.convenience file located at https://github.com/jrosebr1/imutils/blob/master/imutils/convenience.py, you can see how it is implemented.
This is very simple to implement as a one liner in js.
cnts = (cnts.length == 2) ? cnts[0] : (cnts.length == 3) ? cnts[1] : cnts
In second line, max is the inbuilt function of python for iterating through an iterable and to find the maximum based on the key.
This same functionality can be achieved in js as follows
c = cnts.reduce(function(max, cur) {
// here key is the cv2.contourArea function,
// we apply that on the cnts[i] and finds the cnts[i]
// such that cv2.contourArea(cnts[i]) is maximum
if(cv2.contourArea(max) < cv2.countourArea(cur)) {
return cur
} else {
return max
}
});
Now for the third line I assume cv2.minAreaRect function is present in the js version too. I'm not sure though. But hope the above code works for you. Thank you.
The following code is working but extremely slow. Up till the search function all goes well. First, the search function returns a sequence and not an array (why?!). Second, the array consists of nodes and I need URI's for the delete. And third, the deleteDocument function takes a string and not an array of URI's.
What would be the better way to do this? I need to delete year+ old documents.
Here I use xdmp.log in stead of document.delete just te be safe.
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.search(b, ['unfiltered']).toArray();
for (i=0; i<fn.count(c); i++) {
xdmp.log(fn.documentUri(c[i]), "info");
};
Doing the same with cts.uris:
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.uris("", [], b);
while (true) {
var uri = c.next();
if (uri.done == true){
break;
}
xdmp.log(uri.value, "info");
}
HTH!
Using toArray will work but is most likely were your slowness is. The cts.search() function returns an iterator. So All you have to do is loop over it and do your deleting until there is no more items in it. Also You might want to limit your search to 1,000 items. A transaction with a large number of deletes will take a while and might time out.
Here is an example of looping over the iterator
var now = new Date();
var yearBack = now.setDate(now.getDate() - 365);
var date = new Date(yearBack);
var b = cts.jsonPropertyRangeQuery("Dtm", "<", date);
var c = cts.search(b, ['unfiltered']);
while (true) {
var doc = c.next();
if (doc.done == true){
break;
}
xdmp.log(fn.documentUri(doc), "info");
}
here is an example if you wanted to limit to the first 1,000.
fn.subsequence(cts.search(b, ['unfiltered']), 1, 1000);
Several things to consider.
1) If you are searching for the purpose of deleting or anything that doesnt require the document body, using a search that returns URIs instead of nodes can be much faster. If that isnt convenient then getting the URI as close to the search expression can achieve similar results. You want to avoid having the server have to fetch and expand the document just to get the URI to delete it.
2) While there is full coverage in the JavaScript API's for all MarkLogic features, the JavaScript API's are based on the same underlying functions that the XQuery API's use. Its useful to understand that, and take a look at the equivalent XQuery API docs to get the big picture. For example Arrays vs Iterators - If the JS search API's returned Arrays it could be a huge performance problem because the underlying code is based on 'lazy evaluation' of sequences. For example a search could return 1 million rows but if you only look at the first one the server can often avoid accessing the remaining 999,999,999 documents. Similarly, as you iterate only the in scope referenced data needs to be in available. If they had to be put into an array then all results would have to be pre-fetched and put put in memory upfront.
3) Always keep in mind that operations which return lists of things may only be bounded by how big your database is. That is why cts.search() and other functions have built in 'pagination'. You should code for that from the start.
By reading the users guides you can get a better understanding of not only how to do something, but how to do it efficiently - or even at all - once your database becomes larger than memory. In general its a good idea to always code for paginated results - it is a lot more efficient and your code will still work just as well after you add 100 docs or a million.
4) take a look at xdmp.nodeUrl https://docs.marklogic.com/xdmp.nodeUri,
This function, unlike fn.documentUri(), will work on any node even if its not document node. If you can put this right next to the search instead of next to the delete then the system can optimize much better. The examples in the JavaScript guide are a good start https://docs.marklogic.com/guide/getting-started/javascript#chapter
In your case I suggest something like this to experiment with both pagination and extracting the URIs without having to expand the documents ..
var uris = []
for (var result of fn.subsequence(cts.search( ... ), 1 , 100 )
uris.push(xdmp.nodeUri(result))
for( i in uris )
xdmp.log( uris[i] )
I've imported some XML files inside InDesign (you can see the structure in the picture below) and I've also created a script to get some statistics concerning this hierarchy.
For example, to count the "free" elements:
var items = app.activeDocument.xmlElements.everyItem();
var items1 = items.xmlElements.itemByName("cars");
var cars = items1.xmlElements.everyItem();
var c_free = cars.xmlElements.itemByName("free");
var cars_free = c_free.xmlElements.count().length;
I also have apartments in my structure that's why I'm using itemByName.
The code above returns the correct number of free cars in my structure.
What I'm trying to do - without any luck so far - is to target those free items (inside cars) and either delete all of them or a specific number.
My last attempt was using:
var del1 = myInputGroup2.add ("button", undefined, "Delete All");
del1.onClick = function () {
cars.xmlElements.everyItem().remove();
}
inside a dialog I've created.
Any suggestions will be appreciated cause I'm really stuck here.
I would probably use XPath for this. You can use evaluateXPathExpression to create an array of the elements you want to target. Assuming your root element is cars and it contains elements called cars1, and you want to delete all free elements within a cars1 element, you could do something like:
var myDoc = app.activeDocument;
//xmlElements[0] is your root element, in this case "cars". The xPath expression is evaluated from cars.
//evaluateXPathExpression returns an array of all of the free elements that are children of cars.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("cars1/free");
for (var i = myFrees.length - 1; i>=0; i--){
myFrees[i].remove();
}
Tweaking this would require some knowledge of xPath, but it's not terribly hard to learn the basics and it does seem like the simplest approach.
I think your main problem was that XMLElements hasn't a itemByName method. You can only reference XMLElements through their indeces or ids.
Secondly you assume that you got xmlElements from XPath expression but it's likely that you got nothing as your xpath seems uncorrect.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("./cars1/free");
var n = myFrees.length;
if ( !n ) {
alert("Aucun élément trouvé");
}
else {
while (n--) myFrees[n].remove();
}
You need to start your expression by setting the origin of your xpath. Here a dot "./" is used to tell you want to look for cars1/free xml elements at the "root" of the xmlelement. Using "//" on the contrary would have returned any cars/free items unregardingly of their locations.
What I want to accomplish is simple. I want a button's text to change depending on what page your on.
I start this by using the following:
var loc_array = document.location.href.split('/');
Now that I have the url and split it in an array I can grab certain directories depending on the position, like so:
if (loc_array[loc_array.length-1] == 'stations'){
var newT = document.createTextNode("Stations & Maps");
}
Now this works if the directory is /test/stations/, however if someone types /test/stations/index.html then it doesn't work. How can you test against this without throwing in another if statement or using a similar conditional.
Actually both your examples work the same. /stations/ and /stations/index.html both get split into two strings; /stations/ has an empty string at the end. So length-2 would have worked. Where it wouldn't work would be /stations, which is up a level. But that wouldn't normally be an issue because if stations is a static directory, the web server will redirect the browser to /stations/ with the slash.
That won't happen if you're doing the routing yourself. If you're doing routing, it's not a good idea to index from the end of the list of path parts, are there might be any old rubbish there being passed as path-parameters, eg. /stations/region1/stationname2. In this case you should be indexing from the start instead.
If the application can be mounted on a path other than a root you will need to tell JavaScript the path of that root, so it can work out how many slashes to skip. You'll probably also need to tell it for other purposes, for example if it creates any images on the fly it'll need to know the root to work out the directory to get images from.
var BASE= '/path-to/mysite';
var BASELEVEL= BASE.split('/').length;
...
var pagename= location.pathname.split('/')[BASELEVEL];
// '/path-to/mysite/stations/something' -> 'stations'
I'm using location.pathname to extract only the path part of the URL, rather than trying to pick apart href with string or regex methods, which would fail for query strings and fragment identifiers with / in them.
(See also protocol, host, port, search, hash for the other parts of the URL.)
I don't think string splitting is the best approach here. I would do it using RegEx.
var reStations = /\/stations(\/)?/i;
if (reStations.test(document.location.href))
//Do whatever
Not sure exactly what you're looking for, see if this fits:
var loc_array = document.location.href.split('/');
// this will loop through all parts
foreach (var i in loc_array) {
switch (loc_array[i]) {
case "stations":
// do something
break;
// other cases
}
}
// or if you want to check each specific element
switch (loc_array[0]) {
case "stations": // assuming /stations/[something/]
if (typeof loc_array[1] != 'undefined' && loc_array[1] == "something") {
// do things
}
break;
}
if( document.location.href.split( "station" ).length > 1 ){
//...
}
I think I see where you are going with this... As someone stated above using a RegExp (regular expression) could be helpful... but ONLY if you had more than a single type of page to filter out (html/js/php/...), but for what it looks like you want to do. Try something like this:
var loc_array = document.location.href.split('/');
var i = loc_array.length-1;
var button_label = "default";
while(i>1)
{
//checks to see if the current element at index [i] is html
if(loc_array[i].indexOf(".html")>-1)
{
if(i>0)
{
var button_label = loc_array[i-1];
break;
}
}
i--;
}
alert(button_label);
What it does is:
capture the current URL(URI)
split it into an array
starting from the END of the array and working BACKWARDS, look for the first element that contains the ".html" file identifier.
We now know that the element BEFORE our current element contains the label we want to add to our buttons...
You can then take the value and assign it wherever you need it.
If you run out of elements, it has a default value you can use.
Not sure if this helps.....
I have tested the above code and it worked.
if (loc_array[4]=='stations')
if the url was http://www.example.com/test/stations/index.html, the values in the array would be:
[0] = "http:"
[1] = ""
[2] = "www.example.com"
[3] = "test"
[4] = "stations"
[5] = "index.html"
For simplicity's sake, supposing that there is an array of keywords (such as "station") that identify the pages, use a map and try to match its keys with the href string using indexOf,
var href = document.location.href ;
var identifiers = {
"station": "Stations & Maps" , //!! map keys to result strings
/* ... */
} ;
identifier_loop: //!! label to identify the current loop
for(var n in identifiers) { //!! iterate map keys
if( href.indexOf(n) !== -1 ) { //!! true if the key n in identifiers is in the href string
var newT = document.createTextNode( identifiers[n] ) ; //!! create new text node with the mapped result string
break identifier_loop ; //!! end iteration to stop spending ressources on the loop
}
}
Your example will show an empty string, cause the last item is empty; so you can simply make:
if (loc_array[loc_array.length-2] == 'stations')
{
var newT = document.createTextNode("Stations & Maps");
}