Blockly Dictionary Loop

I have created a Blockly Dictionary. But I was not able to loop over it e.g. with “count with … do” or “for each item in list”.

Also “length of” is not working for the dictionary and in the blockly documentation is no example for a loop and a dictionary.

Has anyone experience with dictionaries and blockly?

This works for me

Is this what you intend to do?

Ok. I guess num represents the value and not the key. Is it also possible to access the key with this apporach? I need the key and the value in the loop.

There is a solution that isn’t that elegant but before I come to that, let me explain what is happening here. The blocks generate the following code

myMap = {'key0': 'one', 'key1': 'two', 'key2': 'three'};
for (var num_index in myMap) {
  num = myMap[num_index];
  logger.info(num);
}

So, you can see, it is actually iterating via an index because it perceives it as a index as usually it would use a list-array. However it works, because in that case the index is the key and it is used to lookup the value in the map.

Let’s rename the variable to key and magically the block will create a code that generates a key and a key_index variable

and this code

myMap = {'key0': 'one', 'key1': 'two', 'key2': 'three'};
for (var key_index in myMap) {
  key = myMap[key_index];
  logger.info(('myMap[key_index] =' + String(key)));
}

So the key(index) is actually there but you just can’t access it via a block, right?

well, there is a way of doing it with a trick:

  • define a variable myIndex
  • use a script block to assign the variable key_index to it.

Of course, this is only possible because we know the insights of the block code generation:

… but it does work. For the sake of completeness there is even another less elegant version where we create our own loop :wink: … I leave to the reader to find out why that one works (have a look into the generated code :wink: )

If you want, you can create an issue in github and we may add a special map for-loop in the future…

(actually tricking the blocks was quite fun for me - so thanks for bringing this up :D)

Perfect, solution worked for me.

Opened an issue at Blockly Dictionary loop block with value and key from dictionary · Issue #3373 · openhab/openhab-core · GitHub

And I provided an implementation for it today. Hope you like it.

Morning all, just started with using blockly after transitioning to OH4 recently.

I’m working on some automations to optimize solar export with solar forecasts, and arbitrary target battery soc levels to determine when to switch self consumption mode off (focus on export)
For that purpose dictionary looked to be the easiest method, using the index name as the comparison value, and the value as the desired target.

I have managed to implemente it using the inline script index=key_index method above - which works - but I note there was an an update to add loop support for looping through dictionaries which I presume was intended to allow key indexing? But I’m still running into issues.

Below are the test/comparison functions (not including the inline workarounds above) and the resulting code.
OH4-dict-lookup

I’ve tried implementing using both ‘for each item’ (list), and ‘foreach dictvalue’ (dictionary) but both appear to end up near identical code - only varying by calling it a suffix ‘_index’ rather then ‘Key’ - both then assign the variable to the result of the indexed value - not the index itself ?

// Describe this function...
function Target_SOC_TEST() {
  TARGET_SOC_MAP = {'0': '100', '13': '90', '15': '80', '17': '70', '19': '60', '21': '50'};
  for (var PV_TARGET_INDEX_index in TARGET_SOC_MAP) {
    PV_TARGET_INDEX = TARGET_SOC_MAP[PV_TARGET_INDEX_index];
    console.info(('TEST_LIST_PV_TARGET_INDEX=' + String(PV_TARGET_INDEX)));
  }
  for (var PV_TARGET_INDEXKey in TARGET_SOC_MAP) {
    PV_TARGET_INDEX = TARGET_SOC_MAP[PV_TARGET_INDEXKey];
    console.info(('TEST_DICT_PV_TARGET_INDEX=' + String(PV_TARGET_INDEX)));
  }
  return TARGET_SOC;
}

Edit: the resulting logs are:

2024-10-19 10:29:11.131 [INFO ] - TEST_LIST_PV_TARGET_INDEX=100
2024-10-19 10:29:11.132 [INFO ] - TEST_LIST_PV_TARGET_INDEX=90
2024-10-19 10:29:11.132 [INFO ] - TEST_LIST_PV_TARGET_INDEX=80
2024-10-19 10:29:11.132 [INFO ] - TEST_LIST_PV_TARGET_INDEX=70
2024-10-19 10:29:11.132 [INFO ] - TEST_LIST_PV_TARGET_INDEX=60
2024-10-19 10:29:11.132 [INFO ] - TEST_LIST_PV_TARGET_INDEX=50
2024-10-19 10:29:11.132 [INFO ] - TEST_DICT_PV_TARGET_INDEX=100
2024-10-19 10:29:11.132 [INFO ] - TEST_DICT_PV_TARGET_INDEX=90
2024-10-19 10:29:11.132 [INFO ] - TEST_DICT_PV_TARGET_INDEX=80
2024-10-19 10:29:11.132 [INFO ] - TEST_DICT_PV_TARGET_INDEX=70
2024-10-19 10:29:11.132 [INFO ] - TEST_DICT_PV_TARGET_INDEX=60
2024-10-19 10:29:11.132 [INFO ] - TEST_DICT_PV_TARGET_INDEX=50

Am I missing something obvious or is there a different loop type intended for working with the lookup/index value itself?

Thx again.
Jp

I am away from my computer but did you try as documented here: Rules Blockly - openHAB Extensions to the Standard | openHAB

The problem might be related to the variable because normal vars are not typed and blockly won’t detect it to be a dictionary, so you might want to read this as well: Rules Blockly | openHAB

The loop is defined in the same manner as the second example from your link - using a standard variable as the map with data from a dictionary definition. But I’ll give it a shot to define the map as dictionary type variable first layer this evening when I’m done with other work.

Will update with the results after I’ve tried it.

For now at least the inline code to assign the key/index to a variable and then get the value from the dictionary using it is working.

Thx again

OK, several wrong turns later as it didn’t appear to be adding the type - but removing the blocks, and re-adding them from scratch and it does define a new var named ‘dictionary’ in code which is then assigned the values of the TARGET_SOC_MAP_DICT array, but then appears to index it with a key, assigning the variable to the value rather than the index again?
This also only appears to work with the for each ‘in map’ block.

var dictionary;

// Describe this function...
function Target_SOC_TEST() {
  TARGET_SOC_MAP_DICT = {'0': '100', '13': '90', '15': '80', '17': '70', '19': '60', '21': '50'};
  dictionary=TARGET_SOC_MAP_DICT;
  for (var PV_TARGET_INDEXKey in dictionary) {
    PV_TARGET_INDEX = dictionary[PV_TARGET_INDEXKey];
    console.info(('TEST_DICT_PV_TARGET_INDEX=' + String(PV_TARGET_INDEX)));
  }
  return TARGET_SOC;
}

TARGET_SOC_MAP_DICT typed variable wouldn’t combine with the ‘in list’ block - suggesting it is registering the type now, but the function is then still assigning the PV_TARGET_INDEX TO the value rather than the key/index?

Is there any way to iterate through the key/index names rather than the values?
The inline script you suggested earlier does work - I just thought the update after that added the ability to use the index instead as that was what the workaround addressed?

Thx again.