Recursively listing, and storing, directory contents - objective-c

I know how to recursively list directory contents. I will be using Snow Leopard's enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: method to do this.
However I want to store my findings into a object hierarchy (of, say, objects of a custom FileOrDirectory class that has isLeaf, children, and count attributes).
I need to pre-load the directory and file structure into such a object hierarchy, in order to do whatever I want with NSTreeController and whatnot. I guess the trickiest thing here is to get the children attribute correct in the object hierarchy.
Any ideas?

If I understand your question correctly, you could solve this by writing a recursive function that takes the current node (a file or a folder) and returns an object representing it's structure.
This is Java, but maybe it conveys my idea. I have omitted isLeaf and count, as their values can be derived from the children.
class FileOrFolder
{
String name;
FileOrFolder[] children;
boolean isFile;
}
private FileOrFolder traverse(File file)
{
FileOrFolder fof = new FileOrFolder();
fof.name = file.getAbsolutePath();
if (file.isDirectory())
{
String[] children = file.list();
fof.children = new FileOrFolder[children.length];
for (int i = 0; i < children.length; i++)
{
fof.children[i] = traverse(new File(fof.name + "/" + children[i]));
}
}
fof.isFile = file.isFile();
return fof;
}

Related

Testing child object by the ID of parent Katalon Studio

So I am using a dynamic object and I can receive an API that lists all of the object's properties such as ID in one page, but that ID is the ID of a frame layout that is not interactable and only contains child such as textbox or error message.
what I'm trying to achieve is to know the properties of that parent object so that I can try to interact with the child, for example, the textbox EditText inside. I am able to interact with the child by using the XPath but haven't found a way to determine the parent by the determined ID.
I am trying to make automatic testing that only uses the API as a reference point to check what is the object to test so that in the future I don't have to change the test script in case of any changes in the configuration.
I can check the API for existing object properties like this:
public static checkIfExistForm1(String code){
def response = WS.sendRequest(findTestObject("Object Repository/WebService"))
def json = new JsonSlurper().parseText(response.getResponseBodyContent())
for(int i = 0;i < json.page.form.fieldset.size(); i++){
if(code.contentEquals(json.page.form.fieldset[i].control[0].id)){
return true;
break
}
}
return false;
}
and then I can make some kind of method to get the child of that object and try to interact with it
for example with this method I can select an object by XPath
public static getObjectID(String code){
//considering i know that this is the child, or creating another validation
//the child(EditText) also has ID "content-desc" that i can use
String dynamicIdPath = '//*[#content-desc="%s"]'
String xpath = String.format(dynamicIdPath,code)
TestObject to = new TestObject()
to.addProperty("xpath", ConditionType.EQUALS, xpath)
return to
}
any thoughts? thanks!

gtk#: Tree View object always passed as call-by-reference

It seems as if my arguments in the method call of processing a Tree View is always done as call-by-reference.
I have a visible GTK "Tree View" control on a top level window. The data was written by the respective model.
Now I want to remove some of the columns (based on options set by the user) and pass the manipulated Tree View to an Export-Function.
In order to remove the columns only from the output, not from the GUI itself, I thought of copying the visible Tree View control into a temporary one, manipulating the temportary one and calling the export-functionality on the temporary one.
My problem is: even though I pass my origin, visible Tree View as referenc-by-value (as of my understanding), the origin will be manipulated and the removing of columns will be done on the visual Tree View.
It seem as if my arguments in the method call is always done as call-by-reference.
Code:
"treeview1" is the visual Gtk.Tree View...
I call my Export-function:
...
TreeView treeviewExport = SetExportViewAccordingToCheckboxes(treeview1);
ExportFile(treeviewExport);
...
In the method SetExportViewAccordingToCheckboxes() I just pass the global treeview1 as call-by-value, manipulate it internally and return the manipulated Tree View:
protected static TreeView SetExportViewAccordingToCheckboxes(TreeView tvSource)
{
TreeView tvRet = tvSource;
if (cbName == false)
tvRet.RemoveColumn( ... );
...
return tvRet;
}
But even though I have removed the columns from the internal Tree View "tvRet", my visual control "treeview1" lacks all the columns which were removed from "tvRet"; it looks like "treeview1" was passed as call-by-reference.
Question: why is that?
Note: I also tried with the keyword "in" which made no difference:
protected static TreeView SetExportViewAccordingToCheckboxes(in TreeView p_tvSource)
The problem comes here:
In the method SetExportViewAccordingToCheckboxes() I just pass the
global treeview1 as call-by-value, manipulate it internally and return
the manipulated Tree View:
protected static TreeView SetExportViewAccordingToCheckboxes(TreeView tvSource)
{
TreeView tvRet = tvSource;
if (cbName == false)
tvRet.RemoveColumn( ... );
...
return tvRet;
}
First some background. In C# terminology, value types are those that directly contain a value, while reference types are those that reference the data, instead of holding it directly.
So, int x = 5 means that you are creating the value object 5 of type integer, and storing it in x, while TreeView tree = new TreeView() means that you are creating a reference tree of type TreeView, which points to an object of the same type.
All of this means that you cannot pass an object by value, even if you want to. In the best case, you are passing the reference by value, which has no effect.
So, the next step is to copy the data, and modify the copied object instead of the original one. This is theoretically sound, but the line: TreeView tvRet = tvSource; unfortunately does not achieve that. You are creating a new reference, yes, but that reference points to the same object the original reference points to.
Now, say that we are managing objects of class Point instead of TreeView, with properties x and y.
class Point {
public int X { get; set; }
public int Y { get; set; }
}
You can create a point easily:
Point p1 = new Point { X = 5, Y = 7 };
But this does not copy it:
Point p2 = p1;
This would do:
Point p2 = new Point { X = p1.X, Y = p1.Y };
Now the original problem was that you wanted to pass a few columns to an Export() function. In that case, you only need to pass a vector of the filtered columns to the exporting function, instead of a copy of the TreeView.
void PrepareExporting()
{
var columns = new List<TreeViewColumn>();
foreach(TreeViewColumn col in this.treeView.Columns) {
if ( this.Filter( col ) ) {
columns.add( col );
}
}
this.Export( columns.ToArray() );
}
void Export(TreeViewColumn[] columns)
{
// ...
}
I think that would be easier, since it is not needed to try to achieve a pass-by-reference (impossible), nor copy the tree view.
Hope this helps.

Does this saving/loading pattern have a name?

There's a variable persistence concept I have integrated multiple times:
// Standard initialiation
boolean save = true;
Map<String, Object> dataHolder;
// variables to persist
int number = 10;
String text = "I'm saved";
// Use the variables in various ways in the project
void useVariables() { ... number ... text ...}
// Function to save the variables into a datastructure and for example write them to a file
public Map<String, Object> getVariables()
{
Map<String, Object> data = new LinkedHashMap<String, Object>();
persist(data);
return(data);
}
// Function to load the variables from the datastructure
public void setVariables(Map<String, Object> data)
{
persist(data);
}
void persist(Map<String, Object> data)
{
// If the given datastructure is empty, it means data should be saved
save = (data.isEmpty());
dataHolder = data;
number = handleVariable("theNumber", number);
text = handleVariable("theText", text);
...
}
private Object handleVariable(String name, Object value)
{
// If currently saving
if(save)
dataHolder.put(name, value); // Just add to the datastructure
else // If currently writing
return(dataHolder.get(name)); // Read and return from the datastruct
return(value); // Return the given variable (no change)
}
The main benefit of this principle is that you only have a single script where you have to mention new variables you add during the development and it's one simple line per variable.
Of course you can move the handleVariable() function to a different class which also contains the "save" and "dataHolder" variables so they wont be in the main application.
Additionally you could pass meta-information, etc. for each variable required for persisting the datastructure to a file or similar by saving a custom class which contains this information plus the variable instead of the object itself.
Performance could be improved by keeping track of the order (in another datastructure when first time running through the persist() function) and using a "dataHolder" based on an array instead of a search-based map (-> use an index instead of a name-string).
However, for the first time, I have to document this and so I wondered whether this function-reuse principle has a name.
Does someone recognize this idea?
Thank you very much!

Efficient algorithm for dendrogram cutoff

I have implemented an algorithm for hierarchical clustering and a simple method for drawing the dendrogram in C#.
Now I want to add dendrogram cutoff method and another one for coloring dendrogram branches.
What would be an efficient algorithm to do that?
The cutoff method should return a list of dendrogram nodes beneath which each subtree represents a single cluster.
My data structure is a simple binary tree represented by a Root Node
the node structure is as follows:
class DendrogramNode
{
String Id { get; set; }
DendrogramNode LeftNode { get; set; }
DendrogramNode RightNode { get; set; }
Double Height { get; set; }
}
the CutOff method should have the following signature
List<DendrogramNode> CufOff(int numberOfClusters)
What I did so far:
My first attempt was to create a list of all DendrogramNodes and sort them in descending order. Then take numberOfClusters first entries from the sorted list. - This fails because we may end up with a list containing parent nodes that all children also belong to. In such situation parent nodes should be removed.
Second attempt was to create a list off all linkages and store them in linkage order. This way I could take last numberOfClusters linages and use them to create cutoff list - this works fine, but I don't like to store this information, as it is hard to maintain (specially for iterative clustering)
It sees like a simple problem but somehow I have stacked on this. Can you help me find an efficient solution?
I guess the solution 1 was OK to some point, but then there should be some part that removes parent nodes when all their children are also on the list, ad it should be somehow iterative/recursive, as removing a node creates space to add another.
Good solution is to use PriorityQueue (ites are nodes the priority is node hight):
private List<DendrogramNode> GetCutOffNodes(int numberOfClusters)
{
numberOfClusters = System.Math.Min(this.NumberOfInstances, System.Math.Max(numberOfClusters, 0));
PriorityQueue<DendrogramNode, DendrogramNodeDescendingComparer> queue = newPriorityQueue<DendrogramNode, DendrogramNodeDescendingComparer>();
queue.Enqueue(this.Root);
intclusters2Find = numberOfClusters - 1;
DendrogramNodenode = null;
while(queue.Count > 0 && clusters2Find > 0)
{
node = queue.Dequeue();
if(node.LeftNode != null)
queue.Enqueue(node.LeftNode);
if(node.RightNode != null)
queue.Enqueue(node.RightNode);
clusters2Find--;
}
List<DendrogramNode> result = new List<DendrogramNode>(numberOfClusters);
while(queue.Count > 0)
result.Add(queue.Dequeue());
return result;
}

Returning composite class with Neo4jClient

The Neop4jClient cypher wiki (https://github.com/Readify/Neo4jClient/wiki/cypher) contains an example of using lambda expressions to return multiple projections...
var query = client
.Cypher
.Start(new { root = client.RootNode })
.Match("root-[:HAS_BOOK]->book-[:PUBLISHED_BY]->publisher")
.Return((book, publisher) => new {
Book = book.As<Book>(),
Publisher = publisher.As<Publisher>(),
});
So the query will return details of both book nodes and publisher nodes. But I want to do something slightly different. I want to combine the contents of a single node type with a property of the matched path. Lets say I have Person nodes with a property 'name', and a class defined so,,,
public class descendant
{
public string name { get; set; }
public int depth { get; set; }
}
A cypher query like this will return what I want, which is all descendants of a given node with the depth of the relationship...
match p=(n:Person)<-[*]-(child:Person)
where n.name='George'
return distinct child.name as name, length(p) as depth
If I try a Neo4jClient query like this...
var query =
_graphClient.Cypher
.Match("p=(n:Person)<-[*]-(child:Person)")
.Where("n.name='George'")
.Return<descendant>("child.name, length(p)") ;
I get an error that the syntax is obsolete, but I can't figure out how should I project the cypher results onto my C# POCO. Any ideas anyone?
The query should look like this:
var query =
_graphClient.Cypher
.Match("p=(n:Person)<-[*]-(child:Person)")
.Where((Person n) => n.name == "George")
.Return((n,p) => new descendant
{
name = n.As<Person>().Name,
depth = p.Length()
});
The Return statement should have the 2 parameters you care about (in this case n and p) and project them via the lambda syntax (=>) to create a new descendant instance.
The main point this differs from the example, is that the example creates a new anonymous type, whereas you want to create a concrete type.
We then use the property initializer (code inside the { } braces) to set the name and depth, using the As<> and Length extension methods to get the values you want.
As a side note, I've also changed the Where clause to use parameters, you should always do this if you can, it will make your queries both faster and safer.