Associative Arrays question

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Associative Arrays question

15 Feb 2014, 13:14

Hi!

Having problems with these Associative Arrays again. Spent lots of hours on this but cant find any solution reading the docu. How to get all values from each key separately? I wanna loop through the values in key4 only (NoComskipOnTheseChannels:) and ignore key1, key2 and key3, but cant find a way to do that.

Code: Select all

My_Channels := {"ChannelsForComskip_ini_1": ["Kanal 5", "TV4 Sport", "TV6", "TV8", "Discovery Channel"]
            ,   "ChannelsForComskip_ini_2": ["TV3", "Sjuan", "Animal Planet"]
            ,   "ChannelsForComskip_ini_3": ["TV4"]
            ,   "NoComskipOnTheseChannels":	["SVT1 HD", "SVT2 HD", "SVTB/SVT24", "Kunskapskanalen"] }

for Key1, Value1 in My_Channels {
    ;msgbox % My_Channels[Key1, 1]
    ;msgbox % My_Channels[Key1]	 
	for Key2, Value2 in Value1 {
		;msgbox % Key1 "`n" Value2
		msgbox % My_Channels[Key4]	
	}
}	
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Associative Arrays question

15 Feb 2014, 13:32

Code: Select all

My_Channels := {"ChannelsForComskip_ini_1": ["Kanal 5", "TV4 Sport", "TV6", "TV8", "Discovery Channel"]
            ,   "ChannelsForComskip_ini_2": ["TV3", "Sjuan", "Animal Planet"]
            ,   "ChannelsForComskip_ini_3": ["TV4"]
            ,   "NoComskipOnTheseChannels": ["SVT1 HD", "SVT2 HD", "SVTB/SVT24", "Kunskapskanalen"] }

for Key1, Value1 in My_Channels.NoComskipOnTheseChannels {
	str .= Key1 . " = " . Value1 . "`n"
} 
msgbox,% str
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

15 Feb 2014, 13:46

Aha, so thats how its done...and concatenated and all :D
Many thanks from
zcooler
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Associative Arrays question

15 Feb 2014, 14:00

pleasure to help. btw, offtopic, what is your pvr, comskip setup?
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

15 Feb 2014, 14:36

Im using dvbviewer recording service and launching comskip with an ahk script i found on that forum. Trying to clean up amongst the setupvariables and make it more readable and easier to configure.

What pvr, comskip setup do you use?
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Associative Arrays question

15 Feb 2014, 14:59

Now, I am using tvheadend + xbmc + some scripts and no comskip setup, I just haven't found comskip software for linux. Though I've seen comskip.exe which IIRC You are using. I simply have hoped You are using comskip-something for linux;)
On Windows I had used wmc (whose pvr scheduler is superior to tvheadends).
thx for info
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

15 Feb 2014, 15:11

If using linux i think Wine should take care of launching comskip for u. Wine makes it possible for u to run most windows applications on linux and osx as well. That is what i heard anyway. Could be well worth to investigate further.

Best regards
zcooler
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

15 Feb 2014, 15:29

Hmm, im not that familiar with this xml dom looping code and what is possible to accomplish. I was wondering if there is a way to make it even more efficient with fewer lines and still do what it does today? Maybe its possible to loop all keys and still output all the 5 variables in a single "for key" loop?

Code: Select all

My_Channels := {"ChannelsForComskip_ini_1": ["Kanal 5", "TV4 Sport", "TV6", "TV8", "Discovery Channel"]
            ,   "ChannelsForComskip_ini_2": ["TV3", "Sjuan", "Animal Planet"]
            ,   "ChannelsForComskip_ini_3": ["TV4"]
            ,   "NoComskipOnTheseChannels": ["SVT1 HD", "SVT2 HD", "SVTB/SVT24", "Kunskapskanalen"] }

for Key1, Value1 in My_Channels.ChannelsForComskip_ini_1 {
   ChannelsForComskip_ini_1 .= Value1 ","
} 
msgbox,% ChannelsForComskip_ini_1

for Key1, Value1 in My_Channels.ChannelsForComskip_ini_2 {
   ChannelsForComskip_ini_2 .= Value1 ","
} 
msgbox,% ChannelsForComskip_ini_2

for Key1, Value1 in My_Channels.ChannelsForComskip_ini_3 {
   ChannelsForComskip_ini_3 .= Value1 ","
} 
msgbox,% ChannelsForComskip_ini_3

for Key1, Value1 in My_Channels.NoComskipOnTheseChannels {
   NoComskipOnTheseChannels .= Value1 ","
} 
msgbox,% NoComskipOnTheseChannels

for Key1, Value1 in My_Channels {	 
	for Key2, Value2 in Value1 {
		AllChannels .= Value2 "|"	
	}
}	
msgbox,% AllChannels
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Associative Arrays question

16 Feb 2014, 03:28

Code: Select all

for Key1, Value1 in My_Channels {
	str := Key1 . ": "
    for Key2, Value2 in Value1 {
         str .=  Value2 . ","
    }
    AllChannels .= rtrim(str, ",") . "`n"
}  
msgbox,% AllChannels
There are a many string from/to array functions in the forum(s), and also some json/xml stuff which helps to dump/print objects.
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

16 Feb 2014, 04:49

Fantastic efficiency, I like it much more. I tweaked it a bit for my needs:

Code: Select all

for Key1, Value1 in My_Channels {
    str := ""
    for Key2, Value2 in Value1 {
         str .=  Value2 . ","
    }
    AllChannels .= rtrim(str, ",") . "`n"
}  
StringSplit, OutputArray, AllChannels, "`n"
ChannelsForComskip_ini_1 := OutputArray1
ChannelsForComskip_ini_2 := OutputArray2
ChannelsForComskip_ini_3 := OutputArray3
NoComskipOnTheseChannels := OutputArray4
This code goes way down in the script and wont clutter the configsection. Thanks for your great help strobo :D

Sorry for my noob questions, but i have an another array problem. I keep stumbling on stuff that I suspect are quite basic. In this associative array im trying to disable keys by the only method i know of in order to only use the ones that I see as default. In this case the defaults are MPEG2_ts and H264_ts. My problem is if disabeling last array H264_mkv gets me into trouble, because the last brace also gets disabled.

Maybe there is some other way to disable certain keys in arrays, much smarter way it can be done? If so all pointers are greatly appreciated.

Code: Select all

VideoReDo_Output := {"MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]
;                ,   "MPEG2_mpg": [".mpg" . " " . "/p:""MPEG2 Program Stream"""]
;                ,   "MPEG2_mkv": [".mkv" . " " . "/p:""MPEG2 Matroska MKV"""]
                 ,   "H264_ts":   [".ts" . " " . "/p:""H.264 Transport Stream"""]
;	             ,   "H264_mp4":  [".mp4" . " " . "/p:""H.264 MP4"""]			 
                 ,   "H264_mkv":  [".mkv" . " " . "/p:""H.264 Matroska MKV"""] }

for Key1, Value1 in VideoReDo_Output {	 
	for Key2, Value2 in Value1 {
		default_output_containers .= Value2 "`n"
		msgbox,% VideoReDo_Output[Key1, 1]
	}
}	
msgbox,% default_output_containers
strobo
Posts: 125
Joined: 30 Sep 2013, 15:24

Re: Associative Arrays question

16 Feb 2014, 06:44

If sth like

Code: Select all

array := {
	bla : "bla"
}
is not supported (time ago it wasn't), then, one can try

Code: Select all

VideoReDo_Output := {dummy : ""
;                    ,MPEG2_ts :  [".ts /p:""MPEG2 Transport Stream"""]
                    ,dummy : ""}
or plain (and not quirky)

Code: Select all

VideoReDo_Output := {}
VideoReDo_Output.MPEG2_ts := [".ts /p:""MPEG2 Transport Stream"""]
;VideoReDo_Output.MPEG2_mpg := [".mpg /p:""MPEG2 Program Stream"""]
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Associative Arrays question

16 Feb 2014, 06:46

Code: Select all

VideoReDo_Output :=
(c Join 
{
	  "MPEG2_ts":  [".ts"	" " "/p:""MPEG2 Transport Stream"""]
;	, "MPEG2_mpg": [".mpg"	" " "/p:""MPEG2 Program Stream"""]
;	, "MPEG2_mkv": [".mkv"	" " "/p:""MPEG2 Matroska MKV"""]
	, "H264_ts":   [".ts"	" " "/p:""H.264 Transport Stream"""]
;	, "H264_mp4":  [".mp4"	" " "/p:""H.264 MP4"""]            
	, "H264_mkv":  [".mkv"	" " "/p:""H.264 Matroska MKV"""]
}
)
; note the space at the end of "Join "

Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Associative Arrays question

16 Feb 2014, 07:12

Code: Select all

obj :=
(Join
[
	"Hello",
	"World",
	{
		"key": "value",
		"foo": [
			"bar",
			"test"
		]
	}
]
)

MsgBox, % obj[3].foo[2]
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

16 Feb 2014, 07:22

Aha, so it was a join that was missing! Never could have figured that out. Many thanks trismarck.
Thanks guys for your great help. It was a very needed lesson for me. Now I think i can put the rest together.
Yeah, Olympic gold for Sweden :D
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

16 Feb 2014, 07:53

OMG! Coco, i missed your example cuz i was writing my own post during yours. That is the most efficient code I have seen. These are objects if im not mistaken. Having difficulties to tell things apart you see :) I will experiment with it to see if I can get it to work for my cases. Big thanks!

zcooler
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

16 Feb 2014, 13:45

No, objects does not allow semicolons in expressions to disable keys in arrays.
Using trismarcks example i get in trouble if disabeling the first key, ahk complains about an unexpected comma.
It seems the thing i wanna do is impossible using Associative Arrays. I think I will go with strobos advise using plain (and not quirky) variables. Back to basics and square one in other words when the fancy stuff doesnt work :)

Code: Select all

VideoReDo_Output :=
(c Join 
{
;     "MPEG2_ts":  [".ts"   " " "/p:""MPEG2 Transport Stream"""]
    , "MPEG2_mpg": [".mpg"  " " "/p:""MPEG2 Program Stream"""]
    , "MPEG2_mkv": [".mkv"  " " "/p:""MPEG2 Matroska MKV"""]
    , "H264_ts":   [".ts"   " " "/p:""H.264 Transport Stream"""]
    , "H264_mp4":  [".mp4"  " " "/p:""H.264 MP4"""]            
    , "H264_mkv":  [".mkv"  " " "/p:""H.264 Matroska MKV"""]
}
)
MsgBox, % VideoReDo_Output.MPEG2_mpg[1]
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Associative Arrays question

16 Feb 2014, 16:06

I wonder if there is a way to workaround this. For now, a dummy key-value pair could be used:

Code: Select all

VideoReDo_Output :=
(c Join
{
;	"MPEG2_ts":  [".ts"   " " "/p:""MPEG2 Transport Stream"""], 
    "MPEG2_mpg": [".mpg"  " " "/p:""MPEG2 Program Stream"""],
    "MPEG2_mkv": [".mkv"  " " "/p:""MPEG2 Matroska MKV"""],
    "H264_ts":   [".ts"   " " "/p:""H.264 Transport Stream"""],
    "H264_mp4":  [".mp4"  " " "/p:""H.264 MP4"""],
;   "H264_mkv":  [".mkv"  " " "/p:""H.264 Matroska MKV"""],
	"":[]
}
), VideoReDo_Output.Remove("")

;MsgBox, % VideoReDo_Output.MPEG2_mpg[1]
for k, v in VideoReDo_Output
	out .= v[1] "`n"
MsgBox, % RTrim(out)
Also, why not just:

Code: Select all

VideoReDo_Output :=
(c Join
{
	"MPEG2_ts":  ".ts"   " " "/p:""MPEG2 Transport Stream""",
    "MPEG2_mpg": ".mpg"  " " "/p:""MPEG2 Program Stream""",
    "MPEG2_mkv": ".mkv"  " " "/p:""MPEG2 Matroska MKV""",
    "H264_ts":   ".ts"   " " "/p:""H.264 Transport Stream""",
    "H264_mp4":  ".mp4"  " " "/p:""H.264 MP4""",
	"H264_mkv":  ".mkv"  " " "/p:""H.264 Matroska MKV""",
	"":""
}
), VideoReDo_Output.Remove("")

;MsgBox, % VideoReDo_Output.MPEG2_mpg[1]
for k, v in VideoReDo_Output
	out .= v "`n"
MsgBox, % RTrim(out)
zcooler wrote:No, objects does not allow semicolons in expressions to disable keys in arrays.
Using trismarcks example i get in trouble if disabeling the first key, ahk complains about an unexpected comma.
Autohotkey complains about unexpected comma, because inside of the definition of an associative array object {}, every key-value pair has to be separated from each other by a comma. When the first line is commented out, there is no key-value pair between the { which is the starting point of the definition of the object and the first comma (the comma that acts as a key-value pair separator).
Note that there is no mention about the _semicolon_ (vs about the comma) in the error message. So Autohotkey object syntax _does_ allow semicolons inside of expressions through which (semicolons) key-value pairs can be disabled; the semicolon has nothing to do with the error message (hopefully this is correct).
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

17 Feb 2014, 13:24

Hi trismarck!

Thanks for the workaround and not giving up that easy. It works very well. Didnt realize you could place the commas like that and still have a functional array. On the downside this array got huge and are taking most of the space in the config section. Im hesitant to use it at all, because of that reason.
trismarck wrote:Note that there is no mention about the _semicolon_ (vs about the comma) in the error message. So Autohotkey object syntax _does_ allow semicolons inside of expressions through which (semicolons) key-value pairs can be disabled; the semicolon has nothing to do with the error message (hopefully this is correct).
I was referring to Cocos example when using an array containing an object, then semicolons could not be used at all. The errormessage clearly stated that. Here is the example i meant. Im not sure if i got the code correct though, but it works as long as not using any semicolons:

Code: Select all

obj :=
(Join
[
 {
    "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]
;  , "MPEG2_mpg": [".mpg" . " " . "/p:""MPEG2 Program Stream"""]
  , "MPEG2_mkv": [".mkv" . " " . "/p:""MPEG2 Matroska MKV"""]
  , "H264_ts":   [".ts" . " " . "/p:""H.264 Transport Stream"""]
  , "H264_mp4":  [".mp4" . " " . "/p:""H.264 MP4"""]			 
  , "H264_mkv":  [".mkv"  " " "/p:""H.264 Matroska MKV"""]
 }
]
)

MsgBox, % obj[1].MPEG2_ts[1]
Regards
zcooler
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Associative Arrays question

17 Feb 2014, 15:58

zcooler wrote:Didnt realize you could place the commas like that and still have a functional array.
Actually, the expression _can't_ span multiple lines. It's just that the continuation section (and certain expression operators) work as sort of a preprocessor macro: they 'merge' subsequent lines and create _one_ line. _Later on_, that line is parsed by Autohotkey in search for commands / expressions / other stuff. Note that Join<space> means: join the lines of the continuation section with a space.
zcooler wrote:On the downside this array got huge and are taking most of the space in the config section. Im hesitant to use it at all, because of that reason.
Maybe #include the config section or read the config section from a file. I think serializing AHK associative array objects is possible.
zcooler wrote:I was referring to Cocos example when using an array containing an object, then semicolons could not be used at all. The errormessage clearly stated that. Here is the example i meant. Im not sure if i got the code correct though, but it works as long as not using any semicolons:
Ah, ok, now I get it.

The error from the code above is:

Code: Select all

The leftmost character above is illegal in an expression.
     Specifically: ;
The error occurs because by default, the continuation section _escapes_ all semicolons (so they could be i.e. treated as ~part of the literal text that the continuation section holds). But, if one uses the 'c option of the continuation section, the continuation section _won't_ escape all semicolons, so that those semicolons are treated as source code comments and are discarded by the parser.

I.e.:
Spoiler
//////edit: fixed examples:
before:

Code: Select all

obj :=
(Join
[
 {
    "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]
;  , "MPEG2_mpg": [".mpg" . " " . "/p:""MPEG2 Program Stream"""]
 }
]
)
after:

Code: Select all

obj := [  {     "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]`;  , "MPEG2_mpg": [".mpg" . " " . "/p:""MPEG2 Program Stream"""]  } ]
The escaped comma semicolon `; is not a valid expression token (at that point), thus the error occurs.

before:

Code: Select all

obj :=
(c Join
[
 {
    "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]
;  , "MPEG2_mpg": [".mpg" . " " . "/p:""MPEG2 Program Stream"""]
 }
]
)
after:

Code: Select all

obj := [  {     "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""] } ]
Which is a correct expression.
  • Note that if the c option is present in the continuation section, the order of operations is:
    • remove commented out lines
    • join remaining lines with the character sequence specified after Join
    i.e.:
    if the beginning state is:

    Code: Select all

    obj :=
    (c Join
    [
     {
        "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]
    ;  , "MPEG2_mpg": [".mpg" . " " . "/p:""MPEG2 Program Stream"""]
     }
    ]
    )
    then the effect of the continuation section is:

    Code: Select all

    obj := [  {     "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""] } ]
    and is _not_:

    Code: Select all

    obj := [  {     "MPEG2_ts":  [".ts" . " " . "/p:""MPEG2 Transport Stream"""]
    => If I'd call lines of code that are _directly_ in the script file the 'raw lines' and lines adjoined with the continuation section 'adjoined lines', then, inside of the continuation section, if the c option is used, commented out _raw_ lines are removed (vs ~adjoined lines are commented out) (removal of commented lines works _before_ concatenation of lines, not after concatenation of lines).

The only thing that bothers me with this is: can I have a continuation section that _doesn't_ escape semicolons and at the same time those semicolons are later on part of the expression. The answer is ~: sort of no, because if semicolons are not escaped, they are _always_? treated as comments, even if they are inside of double quotes:

Code: Select all

MsgBox, % "this is ; a text"
; error: Missing close-quote
Which I (along with Scite4Autohotkey syntax highlighter) didn't know.

So I guess the precedence of importance is like this: (from highest to lowest)
  • semicolon
  • double quote
  • comma
I.e.
  • the semicolon is always treated as a comment, even if the semicolon is inside of a double quote.
    MsgBox, % "this is ; a text". Everything after the semicolon is a comment.
  • If the comma is inside of double quotes, that comma is part of the literal string (and not i.e. a parameter separator).
    MsgBox, % "this is , a text". The comma is part of the literal string.
Of course the rules probably change depending on the context, but for now, just for the record of it.
Last edited by trismarck on 21 Feb 2014, 04:46, edited 3 times in total.
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Re: Associative Arrays question

17 Feb 2014, 17:04

You are an amazing teacher trismarck :) This was a great learning experience for me. Many thanks to you!
Now I have a much deeper understanding of how to deal with these arrays that was so mysterious to me before. Its very fun to be abled to utilize different methods from simple arrays to multi-dimensional ones that can get quite complicated. I will visit this thread whenever getting lost again. I am particularly fond of the channel associative array, where i can fit in so much that earlier was variables and it makes the config section much lighter. I have been thinking a long time how to solve that one and now it is in place :D
The Videoredo array I will keep more simple in order to keep config light and easy to follow like this:

Code: Select all

VideoReDo_Output := []
VideoReDo_Output.MPEG2_ts := [".ts /p:""MPEG2 Transport Stream"""]
;VideoReDo_Output.MPEG2_mpg := [".mpg /p:""MPEG2 Program Stream"""]
;VideoReDo_Output.MPEG2_mkv := [".mkv" . " " . "/p:""MPEG2 Matroska MKV"""]
VideoReDo_Output.H264_ts := [".ts" . " " . "/p:""H.264 Transport Stream"""]
;VideoReDo_Output.H264_mp4 := [".mp4" . " " . "/p:""H.264 MP4"""]			 
;VideoReDo_Output.H264_mkv := [".mkv"  " " "/p:""H.264 Matroska MKV"""]
Thank you all for the amazing help, you are the best :D
from
zcooler

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], MrHue and 86 guests