BACnet deserialization: How do I know if a new list elements starts - serialization

I'm implementing a generic BACnet decoder and came across the following question, of which I can't seem to find the answer within the BACnet standard. The chapter "20.2.1.3.2 Constructed Data" does not answer my question, or I might not fully understand it.
Let's assume I have a List (SEQUENCE OF) with elements of type Record (SEQUENCE).
Said record has 4 fields, identified by context tag, where field 0 and 1 are optional.
I further assume that the order, in which those fields are serialized, can be arbitrary (because they're identified by their context tags).
The data could look like that (number indicates field / column):
[{ "3", "0", 2" }, {"1", "2", "3"}]
Over the wire, the only "structure information" I assume I get are the open / close tags for the list.
That means:
Open Tag List
ctxTagColumn3, valueColumn3,
ctxTagColumn0, valueColumn0,
ctxTagColumn2, valueColumn2,
ctxTagColumn1, valueColumn1,
ctxTagColumn2, valueColumn2,
ctxTagColumn3, valueColumn3
Close Tag List
How do I know, after I've read the last column data ("2") of my first list item, that I must begin decoding the second item, starting with a value for column "1"?
Which of my assumptions is wrong?
Thank you and kind regards
Pascal

The order of elements of a SEQUENCE is always known and shall not be arbitrarily by definition. Further, not all conceivable combinations are possible to encode. Regarding BACnet, all type definitions shall be decodable universally.

Assuming I understand you correctly; the "order" cannot be "arbitrary"; i.e.:
SEQUENCE = *ordered* collection of variables of **different** types
SEQUENCE OF = *ordered* collection of variables of **same** type
The tag-number for the item (SD) context-tag will be different (/possibly an incremented value/maybe +1) from the containing (PD) context-tag; so you could check for that, or better still if the tag-number value is <= 5 (/'length' value) then it's a SD context-tag for one of your items, rather than a (/the closing) PD context tag (/'type' value) delimiting the end of your items.

Related

get each number in String and Compare in TCL/tk

I have string output:
1 4 2 1 4
I want to get each character in string to compare.
I did it to want to know whether the list is sorted yet.
It's not exactly clear to me what you are trying to achieve. Going by "to know whether the list is sorted", and assuming a list of integers, you can use tcl::mathop::< or tcl::mathop::<=, depending on whether you want to allow duplicate values:
if {[tcl::mathop::<= {*}$list]} {
puts "List is sorted"
} else {
puts "List is mixed up"
}
This will also work for ASCII comparison of strings. For more complex comparisons, like using dictionary rules or case insensitive, it's probably easiest to combine that with lsort along with the -indices option:
tcl::mathop::< {*}[lsort -indices -dictionary $list]
The -indices option returns the original index of each list element in sorted order. By checking if those indices are in incremental order, you know if the original list was already sorted.
Of course, if the point of the exercise was to avoid unnecessary sorting, then this is no use. But then again, bubble sort of an already sorted list is very fast and will basically do exactly the comparisons you described. So just sorting will probably be faster than first checking for a sorted list via a scripted loop.
To get each character in the string, do split $the_string "" (yes, on the empty string). That gives you a list of all the characters in the string; you can use foreach to iterate over them. Remember, you can iterate over two (or more) lists at once:
foreach c1 [split $the_string ""] c2 $target_comparison_list {
if {$c1 ne $c2} {
puts "The first not equal character is “$c1” when “$c2” was expected"
break
}
}
Note that it's rarely useful to continue comparison after a difference is found as the most common differences are (relative to the target string) insertions and deletions; almost everything after either of those will differ.

Freemarker: Removing Items from One Sequence from Another Sequence

This may be something really simple, but I couldn't figure it out and been trying to find an example online to no avail. I'm basically trying to remove items found in one sequence from another sequence.
Example #1
Items added to the cart is in one sequence; items removed from cart is in another sequence:
<#assign Added_Items_to_Cart = "AAAA,BBBB,CCCC,DDDD,EEEE,FFFF">
<#assign Deleted_Items_from_Cart = "BBBB,DDDD">
The result I'm looking for is: AAAA,CCCC,EEEE,FFFF
Example #2
What if the all items added to and deleted from cart are in the same sequence?
<#assign Cart_Activity = "AAAA,BBBB,BBBB,CCCC,DDDD,EEEE,DDDD,FFFF,Add,Add,Delete,Add,Add,Add,Delete,Add">
The result I'm looking for is the same: AAAA,CCCC,EEEE,FFFF
First things first: You ask about sequence but the data you are dealing with are strings.
I know you are using the string to work as a sequence (and it works), but sequences are sequences and strings are strings, and they have diferente ways of dealing with. I just felt this was important to clarify if someone who is starting to learn how to program get to this answer.
Some assumptions since you're providing strings with data separated by comma:
You want a string with data separated by comma as a result.
You know how to properly create strings with data separated by comma.
You dont have commas in your items names.
Observations:
I'll give you the logic but not the code donne, as this can be a great chance for you to learn/practice freemarker (stackoverflow spirit, you know...)
You question is not about something specific of freemaker (it just happens to be the language you want to work with). Think about adding the logic tag to you question. :-)
Now to the answer on how to do what you want on a "string that is working as a sequence":
Example #1
Change your string to a real sequence :-)
1 - Use a built-in to split your string on commas. Do it for both Added_Items_to_Cart and Deleted_Items_from_Cart. Now you have two real sequences to work with.
2 - Create a new string tha twill be your result .
3 - Iterate over the sequence of added itens.
4 - For each item of the added list, you will check if the deleted list also contains this item.
4.1 - If the deleted list contains the item you do nothing.
4.2 - If the deleted list do not contains the item, you add that item to your string result
At the end of this nested iteration (thats another hint) you should get the result you're looking for.
Example #2
There are many ways of doing it and i'll just share the one that pops out of my mind right now.
I think it's noteworthy that in this approach you will always have an even sized list, as you always insert 2 infos each time: item and action.
So always the first half will be the 'item list' and the second half will be the 'action list'.
1 - Change that string to a sequence (yes, like on the other example).
2 - Get half of its size (in your example size = 16 so half of it is 8)
3 - Iterate over a range from 0 to half-1 (in your example 0 to 7)
4 - At each iteration you'll have a number. Lets call it num (yes I'm very creative):
4.1 - If at the position num + half you have the word "Add" you add the item of position num in your result string
4.2 - If at the position num + half you have the word "Delete" you remove the item of position num from your result string
And for the grand finale, some really usefull links that will help you in your freemarker life forever!!!
All built-ins from freemarker:
https://freemarker.apache.org/docs/ref_builtins.html
All directives from freemarker:
https://freemarker.apache.org/docs/ref_directive_alphaidx.html
Freemarekr cheatsheet :
https://freemarker.apache.org/docs/dgui_template_exp.html#exp_cheatsheet

Are mixed type indexes acceptable in Neo4j?

I have a data set which includes a number of nodes, all of which labeled claim, which can have various properties (names P1, P2, etc., through P2000). Currently, each of the claim nodes can have only one of these properties, and each property has value, which can be of different types (i.e. P1 may be string, P2 may be float, P3 integer, etc.). I also need to be able to look up the nodes by any property (i.e. "find all nodes with P3 which equals to 42").
I have modeled it as nodes having property value and label according to the P property. Then I define schema index on label claim and property value. The lookup then would look something like:
MATCH (n:P569:claim) WHERE n.value = 42 RETURN n
My first question is - is this OK to have such index? Are mixed type indexes allowed?
The second question is that the lookup above works (though I'm not sure whether it uses index or not), but this doesn't - note the label order is switched:
neo4j-sh (?)$ MATCH (n:claim:P569) WHERE n.value>0 RETURN n;
IncomparableValuesException: Don't know how to compare that. Left: "113" (String); Right: 0 (Long)
P569 properties are all numeric, but there are string properties from other P-values one of which is "113". Somehow, even though I said the label should be both claim and P569, the "113" value is still included in the comparison, even though it has no P569 label:
neo4j-sh (?)$ MATCH (n:claim) WHERE n.value ="113" RETURN LABELS(n);
+-------------------+
| LABELS(n) |
+-------------------+
| ["claim","P1036"] |
| ["claim","P902"] |
+-------------------+
What is wrong here - why it works with one label order but not another? Can this data model be improved?
Let me at least try to side-step your question, there's another way you could model this that would resolve at least some of your problems.
You're encoding the property name as a label. Perhaps you want to do that to speed up looking up a subset of nodes where that property applies; still it seems like you're causing a lot of difficulty by shoe-horning incomparable data values all into the same property named "value".
What if, in addition to using these labels, each property was named the same as the value? I.e.:
CREATE (n:P569:claim { P569: 42});
You still get your label lookups, but by segregating the property names, you can guarantee that the query planner will never accidentally compare incomparable values in the way it builds an execution plan. Your query for this node would then be:
MATCH (n:P569:claim) WHERE n.P569 > 5 AND n.P569 < 40 RETURN n;
Note that if you know the right label to use, then you're guaranteed to know the right property name to use. By using properties of different names, if you're logging your data in such a way that P569's are always integers, you can't end up with that incomparable situation you have. (I think that's happening because of the particular way cypher is executing that query)
A possible downside here is that if you have to index all of those properties, it could be a lot of indexes, but still might be something to consider.
I think it makes sense to take a step back and think what you actually want to achieve, and why you have those 2000 properties in the first place and how you could model them differently in a graph?
Also make sure to just leave off properties you don't need and use coalesce() to provide the default.

check if 2 linked list have the same elements regardless of order

Is there any way to check if 2 linked lists have the same elements regardless of order.
edit question:
I have fixed the code and given some more details:
this is the method that compares 2 lists
compare: object2
^ ((mylist asBag) = ((objetc2 getList) asBag)).
the method belongs to the class myClass that has a field : myLList. myList is a linkedList of type element.
I have compiled it in the workspace:
a: = element new id:1.
b:= element new id:2.
c:=element new id:3.
d: = element new id:1.
e:= element new id:2.
f:=element new id:3.
elements1 := myClass new.
elements addFirst:a.
elements addFirst:b.
elements addFirst:c.
elements2 := myClass new.
elements addFirst:d.
elements addFirst:e.
elements addFirst:f.
Transcript show: (elements1 compare:elements2).
so I am getting false.. seems like it checks for equality by reference rather than equality by value..
So I think the correct question to ask would be: how can I compare 2 Bags by value? I have tried the '=='..but it also returned false.
EDIT:
The question changed too much - I think it deserves a new question for itself.
The whole problem here is that (element new id: 1) = (element new id: 1) is giving you false. Unless it's particular class (or superclasses) redefine it, the = message is resolved comparing by identity (==) by default. That's why your code only works with a collection being compared with itself.
Test it with, for example, lists of numbers (which have the = method redefined to reflect what humans understand by numeric equality), and it will work.
You should redefine your element's class' = (and hashCode) methods for this to work.
Smalltalk handles everything by reference: all there exist is an object, which know (reference) other objects.
It would be wrong to say that two lists are equivalent if they are in different order, as the order is part of what a list means. A list without an order is what we call a bag.
The asBag message (as all of the other as<anotherCollectionType> messages) return a new collection of the named type with all the elements of the receiver. So, #(1 2 3 2) is an Array of four elements, and #(1 2 3 2) asBag is a bag containing those four elements. As it's a Bag, it doesn't have any particular order.
When you do bagA := Bag new. you are creating a new Bag instance, and reference it with bagA variable. But then you do bagA := myList asBag, so you lose the reference to the previous bag - the first assignment doesn't do anything useful in your code, as you don't use that bag.
Saying aBool ifTrue: [^true] ifFalse: [^false] has exactly the same meaning as saying ^aBool - so we prefer just to say that. And, as you only create those two new bags to compare them, you could simplify your whole method like this:
compareTo: anotherList
^ myList asBag = anotherList asBag
Read it out loud: this object (whatever it is) compares to another list if it's list without considering order is the same than the other list without order.
The name compareTo: is kind of weird for returning a boolean (containsSameElements: would be more descriptive), but you get the point much faster with this code.
Just to be precise about your questions:
1) It doesn't work because you're comparing bag1 and bag2, but just defined bagA and bagB.
2) It's not efficient to create those two extra bags just because, and to send the senseless ifTrue: message, but other way it's OK. You may implement a better way to compare the lists, but it's way better to rely on the implementation of asBag and the Bag's = message being performant.
3) I think you could see the asBag source code, but, yes, you can assume it to be something like:
Collection>>asBag
|instance|
instance := Bag new.
instance addAll: self.
^instance
And, of course, the addAll: method could be:
Collection>>addAll: anotherCollection
anotherCollection do: [ :element | self add: element ]
So, yes - it creates a new Bag with all the receiver's elements.
mgarciaisaia's answer was good... maybe too good! This may sound harsh, but I want you to succeed if you're serious about learning, so I reiterate my suggestion from another question that you pick up a good Smalltalk fundamentals textbook immediately. Depending on indulgent do-gooders to rework your nonsensical snippets into workable code is a very inefficient way to learn to program ;)
EDIT: The question has changed dramatically. The following spoke to the original three-part question, so I paraphrased the original questions inline.
Q: What is the problem? A: The problem is lack of fundamental Smalltalk understanding.
Q: Is converting to bags an efficient way to make the comparison? A: Although it's probably not efficient, don't worry about that now. In general, and especially at the beginning when you don't have a good intuition about it, avoid premature optimization - "make it work", and then only "make it fast" if justified by real-world profiling.
Q: How does #asBag work? A: The implementation of #asBag is available in the same living world as your own code. The best way to learn is to view the implementation directly (perhaps by "browsing implementors" if you aren't sure where it's defined") and answer your own question!! If you can't understand that implementation, see #1.

How to write additional methods in Smalltalk Collections which work only for Numeric Inputs?

I want to add a method "average" to array class.
But average doesn't make any sense if input array contains characters/strings/objects.
So I need to check if array contains only integers/floats.
Smalltalk says datatype check [checking if variable belongs to a particular datatype like int string array etc... or not] is a bad way of programming.
So what is best way to implement this?
The specification is somewhat incomplete. You'd need to specify what behavior the collection should show when you use it with non-numeric input.
There are a huge number of possibly desirable behaviors. Smalltalk supports most of them, except for the static typing solution (throw a compile-time error when you add a non-numeric thing to a numeric collection).
If you want to catch non-numeric objects as late as possible, you might just do nothing - objects without arithmetic methods will signal their own exceptions when you try arithmetic on them.
If you want to catch non-numeric elements early, implement a collection class which ensures that only numeric objects can be added (probably by signaling an exception when you add a non-numeric object is added).
You might also want to implement "forgiving" methods for sum or average that treat non-numeric objects as either zero-valued or non-existing (does not make a difference for #sum, but for #average you would only count the numeric objects).
In pharo at least there is
Collection >> average
^ self sum / self size
In Collections-arithmetic category. When you work with with a statically typed languages you are being hit by the language when you add non-number values to the collection. In dynamically typed languages you the same happens when you try to calculate average of inappropriate elements e.i. you try to send +, - or / to an object that does not understand it.
Don't think where you put data, think what are you doing with it.
It's reasonable to check type if you want to do different things, e.g.:
(obj isKindOf: Number) ifTrue: [:num| num doItForNum].
(obj isKindOf: Array ) ifTrue: [:arr| arr doItForArr].
But in this case you want to move the logic of type checking into the object-side.
So in the end it will be just:
obj doIt.
and then you'll have also something like:
Number >> doIt
"do something for number"
Array >> doIt
"do something for array"
(brite example of this is printOn: method)
I would have thought the Smalltalk answer would be to implement it for numbers, then be mindful not to send a collection of pets #sum or #average. Of course, if there later becomes a useful implementation for a pet to add itself to another pet or even an answer to #average, then that would be up to the implementer of Pet or PetCollection.
I did a similar thing when I implemented trivial algebra into my image. It allowed me to mix numbers, strings, and symbols in simple math equations. 2 * #x result in 2x. x + y resulted in x + y. It's a fun way to experiment with currencies by imagining algebra happening in your wallet. Into my walled I deposit (5 x #USD) + (15 * #CAN) for 5USD + 15CAN. Given an object that converts between currencies I can then answer what the total is in either CAN or USD.
We actually used it for supply-chain software for solving simple weights and measures. If a purchase order says it will pay XUSD/1TON of something, but the supplier sends foot-lbs of that same thing, then to verify the shipment value we need a conversion between ton and foot-lbs. Letting the library reduce the equation we're able to produce a result without molesting the input data, or without having to come up with new objects representing tons and foot-pounds or anything else.
I had high ambitions for the library (it was pretty simple) but alas, 2008 erased the whole thing...
"I want to add a method "average" to array class. But average doesn't make any sense if input array contains characters/strings/objects. So I need to check if array contains only integers/floats."
There are many ways to accomplish the averaging of the summation of numbers in an Array while filtering out non-numeric objects.
First I'd make it a more generic method by lifting it up to the Collection class so it can find more cases of reuse. Second I'd have it be generic for numbers rather than just floats and integers, oh it'll work for those but also for fractions. The result will be a float average if there are numbers in the collection array list.
(1) When adding objects to the array test them to ensure they are numbers and only add them if they are numbers. This is my preferred solution.
(2) Use the Collection #select: instance method to filter out the non-numbers leaving only the numbers in a separate collection. This makes life easy at the cost of a new collection (which is fine unless you're concerned with large lists and memory issues). This is highly effective, easy to do and a common solution for filtering collections before performing some operation on them. Open up a Smalltalk and find all the senders of #select: to see other examples.
| list numberList sum average |
list := { 100. 50. 'string'. Object new. 1. 90. 2/3. 88. -74. 'yup' }.
numberList := list select: [ :each | each isNumber ].
sum := numberList sum.
average := sum / (numberList size) asFloat.
Executing the above code with "print it" will produce the following for the example array list:
36.523809523809526
However if the list of numbers is of size zero, empty in other words then you'll get a divide by zero exception with the above code. Also this version isn't on the Collection class as an instance method.
(3) Write an instance method for the Collection class to do your work of averaging for you. This solution doesn't use the select since that creates intermediate collections and if your list is very large that's a lot of extra garbage to collect. This version merely loops over the existing collection tallying the results. Simple, effective. It also addresses the case where there are no numbers to tally in which case it returns the nil object rather than a numeric average.
Collection method: #computeAverage
"Compute the average of all the numbers in the collection. If no numbers are present return the nil object to indicate so, otherwise return the average as a floating point number."
| sum count average |
sum := 0.
count := 0.
self do: [ :each |
each isNumber ifTrue: [
count := count +1.
sum := sum + each.
]
].
count > 0 ifTrue: [
^average := sum / count asFloat
] ifFalse: [
^nil
]
Note the variable "average" is just used to show the math, it's not actually needed.
You then use the above method as follows:
| list averageOrNil |
list := { 100. 50. 'string'. Object new. 1. 90. 2/3. 88. -74. 'yup' }.
averageOrNil := list computeAverage.
averageOrNil ifNotNil: [ "got the average" ] ifNil: [ "there were no numbers in the list"
Or you can use it like so:
{
100. 50. 'string'. Object new. 1. 90. 2/3. 88. -74. 'yup'
} computeAverage
ifNotNil: [:average |
Transcript show: 'Average of list is: ', average printString
]
ifNil: [Transcript show: 'No numbers to average' ].
Of course if you know for sure that there are numbers in the list then you won't ever get the exceptional case of the nil object and you won't need to use an if message to branch accordingly.
Data Type/Class Checking At Runtime
As for the issue you raise, "Smalltalk says datatype check [checking if variable belongs to a particular datatype like int string array etc... or not] is a bad way of programming", there are ways to do things that are better than others.
For example, while one can use #isKindOf: Number to ask each element if it's not the best way to determine the "type" or "class" at runtime since it locks it in via predetermined type or class as a parameter to the #isKindOf: message.
It's way better to use an "is" "class" method such as #isNumber so that any class that is a number replies true and all other objects that are not numeric returns false.
A main point of style in Smalltalk when it comes to ascertaining the types or classes of things is that it's best to use message sending with a message that the various types/classes comprehend but behave differently rather than using explicit type/class checking if at all possible.
The method #isNumber is an instance method on the Number class in Pharo Smalltalk and it returns true while on the Object instance version it returns false.
Using polymorphic message sends in this away enables more flexibility and eliminates code that is often too procedural or too specific. Of course it's best to avoid doing this but reality sets in in various applications and you have to do the best that you can.
This is not the kind of thing you do in Smalltalk. You could take suggestions from the above comments and "make it work" but the idea is misguided (from a Smalltalk point of view).
The "Smalltalk" thing to do would be to make a class that could perform all such operations for you --computing the average, mean, mode, etc. The class could then do the proper checking for numerical inputs, and you could write how it would respond to bad input. The class would use a plain old array, or list or something. The name of the class would make it clear what it's usage would be for. The class could then be part of your deployment and could be exported/imported to different images as needed.
Make a new collection class; perhaps a subclass of Array, or perhaps of OrderedCollection, depending on what collection related behaviour you want.
In the new class' at:put: and/or add: methods test the new item for #isNumber and return an error if it fails.
Now you have a collection you can guarantee will have just numeric objects and nils. Implement your required functions in the knowledge that you won't need to deal with trying to add a Sealion to a Kumquat. Take care with details though; for example if you create a WonderNumericArray of size 10 and insert two values into it, when you average the array do you want to sum the two items and divide by two or by ten?