I want to compare two Ansys Mechanical Models and summarize the differences. For some cases it is sufficient to just compare the two ds.dat files with e.g. Notepad++. But different meshes make this comparison quickly confusing.
My idea is to export the tree of the two Models from
ExtAPI.DataModel.Project.Model to two dictionaries and than compare those. But I have difficulties keeping the structure.
When I try to iterate through all Children inspiried by this link with
#recursive function to iterate a nested dictionary
def iterate(dictionary, indent=4):
print '{'
for child in dictionary.Children:
#recurse if the value is a dictionary
if len(child.Children) != 0:
print ' '*indent + child.Name + ": " ,
iterate(child, indent+4)
else:
print ' '*indent+ child.Name
print ' '*(indent-4)+ '}'
I get the structure in a usable format:
iterate(Model)
{
Geometry: {
Part: {
Body1
}
...
}
Materials: {
Structural Steel
}
Cross Sections: {
Extracted Profile1
}
Coordinate Systems: {
Global Coordinate System
} ... }
But now I am strugling with replacing the print statement in the recursive function and keeping the structure from the model tree.
Move it into a dictionary comprehension:
def iterate(dictionary):
return {
child.Name: (iterate(child) if child.Children else None)
for child in dictionary.Children
}
The output will be:
{
"Geometry": {
"Part": {
"Body1": None
},
...
},
"Materials": {
"Structural Steel": None,
}
"Cross Sections": {
"Extracted Profile1": None,
}
"Coordinate Systems": {
"Global Coordinate System": None
} ... }
You can use pprint.pprint() if you wish to format it nicely for presentation.
Related
Given a nested map/list/scalar data structure in Groovy, does it have any pretty "Groovy" way to walk it and produce a transformed structure?
The cleanest way I've written so far isn't too bad, a recursive walker that applies a closure. But I'd welcome advice if there's a built-in way I am missing.
For example, take this data structure and replace all instances of ${VARIABLE} with REPLACED in Strings within it:
def config = [
'${VARIABLE}: 'scalar',
'foo': [
'bar': 1,
'baz': ['a', 'b', 'c', 'd'],
'my_${VARIABLE}_key': null
],
'bak': 1,
'ban': 'abcd',
'boo': [
['x': 1, 'y': 2, 'subst': '${VARIABLE}'],
['a': 1, 'b': 2]
]
]
Here's the best I've come up with so far:
def walk(v, Closure transform ) {
switch (v) {
case null:
return null
case Map:
return v.collectEntries { mk, mv -> [ transform(mk), walk(mv, transform) ] }
case List:
return v.collect { lv -> walk(lv, transform) }
default:
return transform(v)
}
}
which given the above example data, may be applied like:
def engine = new groovy.text.SimpleTemplateEngine()
def subs = ['VARIABLE': 'REPLACED']
def newconfig = walk(config) { v ->
switch (v) {
case String:
return engine.createTemplate(v).make(subs)
default:
return v
}
}
This relies on Groovy's smart switch statement. It's not extensible, you can't just plug in your own type handlers, but it's so simple you don't need to. It does a hybrid copy by default, making new instances of Lists and Maps but retaining references to the original scalar or unmatched types. It can be made to deep copy too, per the following identity transform examples:
// Identity transform, shallow copy scalars
assert (config == (walk(config) { v -> v.clone() }))
// Identity transform, deep copy scalars where possible
assert (config == (walk(config) {
v ->
try {
return v.clone()
} catch (java.lang.CloneNotSupportedException ex) {
return v
}
}))
Thoughts? Better ways?
I have this body request example:
{
"users": [{
"userId": 123
}, {
"userId": 1234
}]
}
For the previous example I receive one std::list<UsersId>* VUsers that have my userId (in this case '123' and '1234'), create cJSON array, iterate my list and get all userId. (Note: the UsersId is one auxiliar class that I use and receive one int in constructor)
cJSON* cJsonUsers = cJSON_CreateArray();
cJSON_AddItemToObject(root, "VUsers", cJsonUsers);
std::list<UsersId>::const_iterator itUsers = VUsers->begin();
while (itUsers != VUsers->end())
{
cJSON *cJsonVNode = cJSON_CreateObject();
cJSON_AddItemToArray(cJsonUsers, cJsonUser);
cJSON_AddNumberToObject(cJsonUser, "userId", itUsers->userId);
++itVNodes;
}
But know I want to the same but make more simple/easy and need to change the body request to something like this:
{
"users": {
"userId": [123, 1234]
}
}
I'm using this c++ library -> https://github.com/DaveGamble/cJSON but I dont understand how to do to implement the modification that I need.
EDIT 2 (PARSE THE JSON)
cJSON* cJsonUsers = cJSON_GetObjectItem(root, "users");
if (!cJsonUsers) return 0;
if (cJsonUsers->type != cJSON_Array) return 0;
std::list<VUserId>* users = new std::list<VUserId>();
cJSON* cJsonVUser;
cJSON_ArrayForEach(cJsonVUser, cJsonUsers)
{
cJSON* cJsonVUserId = cJSON_GetObjectItem(cJsonVUser, "userId");
if (!cJsonVUserId) continue;
int user_id = cJsonVUserId->valueint;
VUserId userId(user_id);
users->push_back(userId);
}
Something like this could work, that is, create the object and array outside of the loop, and insert the numbers inside the loop:
cJSON* cJsonUsers = cJSON_CreateObject();
cJSON_AddItemToObject(root, "users", cJsonUsers);
cJSON* cJsonUserId = cJSON_CreateArray();
cJSON_AddItemToObject(cJsonUsers, "userId", cJsonUserId);
std::list<UsersId>::const_iterator itUsers = VUsers->begin();
while (itUsers != VUsers->end())
{
cJSON_AddItemToArray(cJsonUserId, cJSON_CreateNumber(itUsers->userId));
++itVNodes;
}
Note that there are languages out there that are more convenient to manipulate JSON if you have the flexibility (disclaimer: I was involved in the design of some of these). Of course there are always use cases when you have to use C++ and in which a library makes a lot of sense.
With languages such as C++ or Java, there is an impedance mismatch between objects in the classical sense, and data formats like XML or JSON. For example, with the standardized, declarative and functional XQuery 3.1 this does not need much code to transform the first document into the second:
let $original-document := json-doc("users.json")
return map {
"users" : map {
"userId" : array { $original-document?users?*?userId }
}
}
I've abstracted a very simple situation here, in which I want to pass a list of strings into my cleanLines function and get a list of strings back out. Unfortunately, I'm new to Groovy and I've spent about a day trying to get this to work with no avail. Here's a stand-alone test that exhibits the problem I'm having:
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
class ConfigFileTest {
private def tab = '\t'
private def returnCarriage = '\r'
private def equals = '='
List <String> cleanLines(List <String> lines) {
lines = lines.collect(){it.findAll(){c -> c != tab && c != returnCarriage}}
lines = lines.findAll(){it.contains(equals)}
lines = lines.collect{it.trim()}
}
#Test
public void test() {
List <String> dirtyLines = [" Colour=Red",
"Shape=Square "]
List <String> cleanedLines = ["Colour=Red",
"Shape=Square"]
assert cleanLines(dirtyLines) == cleanedLine
}
}
I believe that I've followed the correct usage for collect(), findAll() and trim(). But when I run the test, it crashes on the trim() line stating
groovy.lang.MissingMethodException: No signature of method:
java.util.ArrayList.trim() is applicable for argument types: ()
values: []
. Something's suspicious.
I've been staring at this for too long and noticed that my IDE thinks the type of my first lines within the cleanLines function is List<String>, but that by the second line it has type Collection and by the third it expects type List<Object<E>>. I think that String is an Object and so this might be okay, but it certainly hints at a misunderstanding on my part. What am I doing wrong? How can I get my test to pass here?
Here's a corrected script:
import groovy.transform.Field
#Field
def tab = '\t'
#Field
def returnCarriage = '\r'
#Field
def equals = '='
List <String> cleanLines(List <String> lines) {
lines = lines.findAll { it.contains(equals) }
lines = lines.collect { it.replaceAll('\\s+', '') }
lines = lines.collect { it.trim() }
}
def dirtyLines = [" Colour=Red",
"Shape=Square "]
def cleanedLines = ["Colour=Red", "Shape=Square"]
assert cleanLines(dirtyLines) == cleanedLines
In general findAll and collect are maybe not mutually exclusive but have different purposes. Use findAll to find elements that matches certain criteria, whereas collect when you need to process/transform the whole list.
this line
lines = lines.collect(){it.findAll(){c -> c != tab && c != returnCarriage}}`
replaces the original list of Strings with the list of lists. Hence NSME for ArrayList.trim(). You might want to replace findAll{} with find{}
You can clean the lines like this:
def dirtyLines = [" Colour=Red", "Shape=Square "]
def cleanedLines = ["Colour=Red", "Shape=Square"]
assert dirtyLines.collect { it.trim() } == cleanedLines
If you separate the first line of cleanLines() into two separate lines and print lines after each, you will see the problem.
it.findAll { c -> c != tab && c != returnCarriage }
will return a list of strings that match the criteria. The collect method is called on every string in the list of lines. So you end up with a list of lists of strings. I think what you are looking for is something like this:
def cleanLines(lines) {
return lines.findAll { it.contains(equals) }
.collect { it.replaceAll(/\s+/, '') }
}
Hello I am trying to create a list of json objects in groovy
List relClinicStatementList = []
for (BloodTestRow row in BTList){
def jsonListBuilder = new groovy.json.JsonBuilder()
def internalJson = jsonListBuilder{
'targetRelationshipToSource' {
'code' 'part-of'
'codeSystem' 'MG'
}
'observationResult'{
'observationFocus'{
'code' "${row.exam}"
'codeSystem' 'mobiguide'
'displayName' "${row.exam}"
}
'observationValue' {
'physicalQuantity' {
'value' "${row.value}"
'unit' "${row.unit}"
}
}
}
}
println jsonListBuilder.toPrettyString()
relClinicStatementList.add(internalJson)
}
And the toPrettyString() method correctly shows the json structure I want.
However if at the end of the loop I try to print all of the items I have in the list like this:
for (JsonBuilder entry in relClinicStatementList){
println entry.toPrettyString()
}
I get all the elements inside my relClinicalStatement list to be equal to the latest I created... I felt like declaring a new JsonBuilder at each loop would prevent this behaviour... am I missing something? I must admit I come from Java and have the feeling that using groovy classes here makes this behave a little differently from what I expect.
How do I solve this issue?
Thanks in advance
I can't reproduce the behaviour you are seeing, but I think the problem is that I don't believe internalJson is what you think it is (it's a list of 2 closures).
If you change your code to:
List relClinicStatementList = btList.collect { row ->
new groovy.json.JsonBuilder( {
targetRelationshipToSource {
code 'part-of'
codeSystem 'MG'
}
observationResult {
observationFocus {
code "$row.exam"
codeSystem 'mobiguide'
displayName "$row.exam"
}
observationValue {
physicalQuantity {
value "$row.value"
unit "$row.unit"
}
}
}
} )
}
relClinicStatementList.each { entry ->
println entry.toPrettyString()
}
Does it work as you'd expect?
Hi i have this ember model. The likeMessage computed Property is building a string that i am using in my template. (see below)
This works, but i'm not comfortable having this "view layer code" in my model. What would be a better approach?
/**
* #class
* #name Entry
*/
James.Entry = Ember.Object.extend(
/** #lends Entry# */
{
likes: [],
likeMessage: function() {
var likes = this.get("likes"),
withNameCount = 0,
names = [],
likeCount = likes.length;
for(;withNameCount < likes.length && withNameCount < 2; withNameCount++) {
names.push(likes[withNameCount].name);
}
if(likeCount == 0) {
return "Nobody likes this";
} else if(likeCount == 1) {
return names[0]+ " likes this";
} else if(likeCount <= 2) {
return names.join(" and ")+" like this";
} else {
return names.join(", ")+" and "+(likes.length-2)+" others like this";
}
}.property("likes")
}
);
My template:
Likes:
{{likeMessage}}
Computed properties that are for presentation belong in the controller layer in Ember. To get easy access to the model, you can use an Ember.ObjectController and set the content property to the model instance you are showing.
I recently put together a presentation recently about what goes where when architecting an Ember app. Perhaps it could be useful: http://www.lukemelia.com/blog/archives/2012/08/23/architecting-ember-js-apps/
You could move that method pretty much as is to an EntryView and then call view.likeMessage in the template.
Without knowing your View classes I cannot be more specific but typically you would have a corresponding view for every model (often two, one "singular" and one "plural" for handling collections or single instances of the model).