I’m having trouble sorting a list of values and names. The objective is to archive the following:
I get distance values for BLE beacons from 3 different ESP32 via MQTT. For each beacon I want to figure out to which ESP32 it is closest to and get the room name. I’m not very familiar with java so I ‘frankensteined’ a peace of code from this forum yet I can’t figure out how to do the sorting. My idea looks like that:
import java.util.HashMap
import java.util.Collections
rule "Raumanwesenheit Lars"
when
// Wenn ein Distanzwert sich ändert
Item SMW_Lars_Kueche_Distance changed or
Item SMW_Lars_Wohnzimmer_Distance changed or
Item SMW_Lars_Schlafzimmer_Distance changed
then
// Neue HashMap anlegen
val HashMap<DecimalType, String> distancesLars = new HashMap
// Wenn einer der Distanzwerte nicht NULL ist
if( (SMW_Lars_Kueche_Distance.state as DecimalType) !== NULL ||
(SMW_Lars_Wohnzimmer_Distance.state as DecimalType) !== NULL ||
(SMW_Lars_Schlafzimmer_Distance.state as DecimalType) !== NULL ) {
// Die Distanzwerte mit dem dazugehörigen Raum in die Liste schreiben
if( (SMW_Lars_Kueche_Distance.state as DecimalType) !== NULL ) {
distancesLars.put(SMW_Lars_Kueche_Distance.state as DecimalType, "Kueche")
}
if( (SMW_Lars_Wohnzimmer_Distance.state as DecimalType) !== NULL ) {
distancesLars.put(SMW_Lars_Wohnzimmer_Distance.state as DecimalType, "Wohnzimmer")
}
if( (SMW_Lars_Schlafzimmer_Distance.state as DecimalType) !== NULL ) {
distancesLars.put(SMW_Lars_Schlafzimmer_Distance.state as DecimalType, "Schlafzimmer")
}
// Here the trouble begins...
// Distanzwerte sortieren und Raumname mit der kleinsten Distanz auslesen - hier gibts Probleme
val distancesLarsSorted = Collections.sort(distancesLars)
val roomName = distancesLars.get(distancesLarsSorted.get(0))
// Belegten Raum in das Item schreiben
SMW_Lars_Occupies.postUpdate(roomName)
}
// Wenn alle Distanzwerte NULL sind
else {
SMW_Lars_Occupies.postUpdate("Abwesend")
}
end
Unfortunately that doesn’t work. I’m getting the following error:
Type mismatch: cannot convert from HashMap<DecimalType, String> to List<Comparable<?>>(org.eclipse.xtext.xbase.validation.IssueCodes.incompatible_types)
What am I missing here?
Thanks in advance for any clues on getting that work.
I’m pretty sure there is no method .sort on collections. At least, it is not mentioned in Oracle Help Center…
So, I guess you would have to create a function first…
But maybe there is a much more convenient way, by using groups. Just create a group gLars_Distance and put all thos SMW_Lars_xxx_Distance Items in this group (no need for Aggregation nor special Group Item Type), Now, in the rule:
rule "Raumanwesenheit Lars"
when
Member of gLars_Distance changed // if at least one value changed
then
var String strRoom = ""
if(gLars_Distance.members.filter[i|i.state instanceof Number].size > 0) { // at least one value valid
val shortest = gLars_Distance.members.filter[i|
i.state instanceof Number].sortBy[ state as Number ].head // get a list of valid bvalues, sort from status, get the first item
strRoom = shortest.name.split("_").get(2) // get the room name
} else { // if no valid value
strRoom = "Abwesend" // set to absent
}
SMW_Lars_Occupies.postUpdate(strRoom) // write to item
end
You cannot sort a Map. But you can take the key set and sort this. Because the keys are numbers, they are comparable and can be sorted.
val sortedKeys = distancesLars.keySet().stream().sorted().collect(Collectors.toList());
val firstKey = sortedKeys.get(0);
val firstItem = distancesLars.get(firstKey);
But the problem is @gooselk, you have a Map, not a List. What does it even mean to sort a Map? Do you sort by the values? By the Keys? Both? The link provided by @rossko57 shows lots of your options as does @franks. I’ll provide one more.
The biggest difference between mine and franks’ solution is I’m pretty sure that Rules DSL does the stream stuff for you. So you could do something like:
thanks for the input so far. As I said, I am quite new to all this and have put the code together in a way that made sense for me. Yet I do not seem to have my head wrapped around the concepts of Maps and Lists yet…
Your solution looks promising yet I do get an error on this line stating:
Bounds mismatch: The type arguments <Item, State> are not a valid substitute for the bounded type parameters <T, C extends Comparable<? super C>> of the method sortBy(Iterable<T>, Function1<? super T, C>)(org.eclipse.xtext.xbase.validation.IssueCodes.type_bounds_missmatch)
A collection of key/value pairs. The key is used as the index to retrieve the corresponding value.
You are using a Map. There’s a key and a value.
You need to import Collectors.
import java.util.stream.Collectors
As I mentioned, a Set is unordered. So it seems it doesn’t make sense to try to sort it. Rules DSL sometimes falls down on doing this sort of type checking so using the stream like @franks demonstrates is probably the best approach.