Can I loop in Pashua to return the variables with a boolean of 1?

I’m using Applescript with github.com/BlueM/Pashua. I’m using checkboxes in the dialog box, and I can get the output of those as a result in the script editor, i.e., when cat and cat 2 are checked, I get:

But what I need to do is loop through the checkboxes to find only those that have been toggled to 1, and I don’t know where to start.

How can I loop through all categories - cat, cat2, cat3, cat4, etc. - in the result, find only those that are boolean 1, and then output those in one variable, separated by a comma?

I.e. using this script result

how can I loop through and get a variable that has a value of:

This is the script that generates the dialog box and the checkboxes:

tell application "Finder" to set thisFolder to (container of (path to me)) as text -- get the folder path
    try
    	set thePath to alias (thisFolder & "Pashua.scpt")
    	set pashuaBinding to load script thePath
    	
    	tell pashuaBinding
    		try
    			set dialogConfiguration to my getDialogConfiguration() -- configure the dialog
    			set dialogResult to showDialog(dialogConfiguration, "") -- show the dialog
    			
    		end try
    	end tell
    end try
    
    on getDialogConfiguration() -- return the configuration string
    	return "
    
    # Add category checkboxes
    txtcats.type = text
    txtcats.default = Categories
    cat.rely = -18
    cat.type = checkbox
    cat.label = Category 1
    cat2.type = checkbox
    cat2.label = Category 2
    cat3.type = checkbox
    cat3.label = Category 3
    cat4.type = checkbox
    cat4.label = Category 4
    
    "
    end getDialogConfiguration

AppleScript: 2.7
Browser: Firefox 73.0
Operating System: macOS 10.14

I do not know if the following is suitable for you:


global aRecord

set aRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}
set theKeys to {}
set filteredList to {}

-- GET THE KEYS OF THE RECORD (as LIST OF STRINGS)
set the clipboard to aRecord
set aRecordAsList to list of (get the clipboard)
repeat with i from 1 to count aRecordAsList by 2
	set end of theKeys to item i of aRecordAsList
end repeat
--> RESULT: theKeys = {"cat", "cat4", "cat2", "cat3", "cat78", "dog56", "Camel_2", "BigCamel_15"}

-- FILTER THE KEYS LIST and RETURN THE FILTERED LIST
repeat with i from 1 to count theKeys
	set theKey to item i of theKeys
	if getWhat(theKey) is "1" then set end of filteredList to theKey
end repeat
return filteredList
--> RESULT: filteredList = {"cat", "cat2", "cat78", "dog56", "BigCamel_15"}

-- HANDLER TO GET THE VALUE OF KEY BY IT'S STRING REPRESENTATION
on getWhat(what)
	set s to "on run {aRecord}
get " & what & " of aRecord
end"
	run script s with parameters {aRecord}
end getWhat

The definition of a record as shown in the AppleScript Language Guide is:

Given the above, I don’t believe it’s possible to loop through a record as one can loop through a list. One alternative is to coerce the record into some other format, as KniazidisR has done, and this works well. I’ve included a second alternative below–it’s simplistic but it’s very fast and does the job if the number of checked boxes is small. A third alternative is not to create a list of labels of checked boxes and instead to test for checked boxes in the main body of the script where needed.

I am not very knowledgeable on this topic and look forward to responses from other forum members.

set theRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0"}
set checkedItems to {}

if cat of theRecord = "1" then set the end of checkedItems to "cat"
if cat4 of theRecord = "1" then set the end of checkedItems to "cat4"
if cat2 of theRecord = "1" then set the end of checkedItems to "cat2"
if cat3 of theRecord = "1" then set the end of checkedItems to "cat3"

checkedItems --> {"cat", "cat2"}

Coercing a record as list is a very bad answer because we can’t guarantee the order of the different items in a record.
In old days we have no alternative so we were forced to play with matches.
Nowadays, thanks to ASObjC and it’s records, we may play safe.

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

set aRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}

set theDict to current application's NSDictionary's dictionaryWithDictionary:aRecord
if theDict is not missing value then
	-- make an array with the keys
	set theKeys to theDict's allKeys()
	-- create a mutable array in which we will put the keys whose value is "1"
	set theFilteredList to current application's NSMutableArray's new()
	repeat with aKey in theKeys
		if (theDict's valueForKey:aKey) as string = "1" then
			(theFilteredList's addObject:(aKey as text))
		end if
	end repeat
end if
-- convert the mutable array in an AS list
theFilteredList as list--> {"BigCamel_15", "cat2", "cat", "cat78", "dog56", "Camel_2"}

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 12 mars 2020 19:05:25

Please note - my script uses the clipboard. That is why it preserves the order of the keys. What your AsObjC version does not do.

By definition, the labels are unordered, so it doesn’t matter what you do – there’s no guarantee that order will be maintained. In practice, the order is, as it with coercion. That’s a reflection of the underlying way AppleScript code stores and manipulates records, but at least in theory, it could change. (The chances at this stage are obviously miniscule.)

I’m uncomfortable about relying on something the documentation suggests one shouldn’t, whatever the practicalities, unless there’s some very good reason. And I’ve seen it lead to disaster where order can and does change: when applications return results as records.

Yes, I have already seen on the net statements like yours, Yvan Koenig and some others: 1) It is not possible to safely obtain a list of record’s keys using simple AppleScript, 2) it is not possible to preserve the order of the keys.

You didn’t like the fact that my script refutes both statements. Yes, I know that the order does not matter for the record, but let don’t forget that it has or may matter for the resulting list. And I did not pay attention to the order. Yvan Koenig rests on him. He say: “bla-bla-bla, only AsObjC is safe” and so on… Well, this person is hard to convince of something. Especially in something new that he had not yet met. I have been convinced of this more than once. But I expect more understanding from you

Not at all – I didn’t actually look at your script, just the argument. But when I look at it now I’m a bit baffled: passing to and from the clipboard in that script does nothing useful. You could just as easily write:

set aRecordAsList to list of {list:aRecord}

The order isn’t preserved because of the clipboard – it’s preserved because of the way AppleScript stores records, in this case combined with the fact that none of the record labels are reserved words (if they were, your script would fail and Yvan’s would simply ignore those values).

I tried. Unfortunately, I can’t accept your code as the best, since it, unlike the clipboard, rearranges keys in alphabetical order. You must understand that in my script I use the wonderful property of the clipboard to work on the principle of a memory stack. The order is always kept in the stack.

I didn’t post any code. And Yvan’s doesn’t use alphabetical order, either.

With respect, you’re kidding yourself. The order is kept because of the way AppleScript stores records – no more, no less.

I’m sorry: your code


set aRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}
set aRecordAsList to list of {list:aRecord}
--> RESULT: {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}

is not rearranging the order of the keys in alphabetical order. The Variables’s window of Script Debugger shows them in alphabetical order. It was it that led me astray. But still, your code is not what I need. Your code line is equivalent to reassigning the record to itself. It doesn’t create the list, but the same record:


set aRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}
set aRecordAsList to aRecord
--> RESULT: {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}

This keeps the order of the keys as you see the record visually, and creates list:


set aRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}
set the clipboard to aRecord
set aRecordAsList to list of (get the clipboard)
--> RESULT: "cat", "1", "cat4", "0", "cat2", "1", "cat3", "0", "cat78", "1", "dog56", "1", "Camel_2", 1, "BigCamel_15", "1"}

Then, knowing that at every odd position there is a key, I can extract them:


set theKeys to {}
repeat with i from 1 to count aRecordAsList by 2
	set end of theKeys to item i of aRecordAsList
end repeat
--> RESULT: theKeys = {"cat", "cat4", "cat2", "cat3", "cat78", "dog56", "Camel_2", "BigCamel_15"}

It seems that you didn’t read carefully Shane’s comment.

try to run:

set aRecord to {cat:"1", cat2:"0", string:"1", text:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}
set the clipboard to aRecord
set aRecordAsList to list of (get the clipboard)

You will get an infamous but logical : error “Il est impossible d’obtenir list of "1".” number -1728 from list of “1”

As the original set of data is created by a tool which is not related to AppleScript, it may perfectly contain keys like string or text which aren’t valid in AppleScript’s records.

If you pass the same original record to my script, you will get :
{“cat”, “dog56”, “cat78”, “BigCamel_15”, “Camel_2”}
which contain every valid items matching the rule.

I really don’t understand what let you thing that something was linked to alphabetical ordering.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 13 mars 2020 10:15:19

Your catch is intended only for simpletons who do not know how to use a reserved word in AppleScript: |string|, |text|.
You would have set up a living elephant there, why not?

And, even with living elephants, the plain AppleScript can create an ordered list, keeping the valid keys:


set aRecord to {cat:"1", cat2:"0", string:"1", text:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}

set the clipboard to aRecord
set aRecordAsList to the clipboard as list

Let’s use more elephants, and less normal key names. This is getting fun:


set aRecord to {text:"1", string:"0", file:"1", window:"0", list:"1", record:"1", clipboard:1, onlyOneSmallCamel_15:"1"}

set the clipboard to aRecord
set aRecordAsList to the clipboard as list

Forgive me if I’m being blunt, but much of this discussion seems besides the point.
That point being that you cannot rely on the order of properties in a record returned by an external agent. It may be that said order seems fixed in specific circumstances, like a given Pashua configuration; it still is fundamentally unsound to rely on that seemingly fixed order.

If a script must know the value of specific properties it should ask for them, and not manipulate the record that contains them. You’d be getting into a bad habit when doing that.
Peavine’s M.O. is the one to go for, in my book.

Thanks alastor933–I agree. We know little about the OP’s script but an issue that should at least be raised is whether the OP actually needs to create a list of labels of checked boxes and might instead directly test the value of the applicable property.

@peavine
One drawback remains: you MUST know the name of the keys available in the record to apply your scheme.

@KniazidisR
Your very last proposal works BUT it’s different that the ones which were commented.
I must recognize that your proposal, at least to my knowledge, is the first one which gives an ‘old fashioned’ answer to a question asked since the creation of AppleScript : how to get the name of the keys available in a record ?

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 13 mars 2020 15:27:40

Just as a matter of terminology, a record is defined in the ASLG as quoted below. I assume that forum members who use the word key are referring to a label.

@Yvan. I believe the label names are directly obtained from the script.

I like simple scripts. And I know that everything ingenious is simple. I also never had anything to do with Pashua, and most likely, instead of the record, you can get a list of checkbox names, and then filter this list in a loop according to the state of the checkboxes. But:

  1. Unfortunately, the question in the topic is clear: “can I loop…?” and the OP has a record. Peavine’s solution does not have a repeat loop, but hardcoded variables, so it doesn’t suit me (in this case).

  2. From the conversation with Yvan Koenig I got 1 favor: instead of:

set aRecordAsList to list of (get the clipboard)

it’s better to use

set aRecordAsList to the clipboard as list

.
So, the updated version should be like this:


global aRecord

set aRecord to {cat:"1", cat4:"0", cat2:"1", cat3:"0", cat78:"1", dog56:"1", Camel_2:1, BigCamel_15:"1"}
set theKeys to {}
set filteredList to {}

-- GET VALID KEYS OF THE RECORD (as LIST OF STRINGS)
set the clipboard to aRecord
set aRecordAsList to the clipboard as list -- EDITED, THANKS TO YVAN KOENIG
repeat with i from 1 to count aRecordAsList by 2
	set end of theKeys to item i of aRecordAsList
end repeat
--> RESULT: theKeys = {"cat", "cat4", "cat2", "cat3", "cat78", "dog56", "Camel_2", "BigCamel_15"}

-- FILTER THE KEYS LIST and RETURN THE FILTERED LIST
repeat with i from 1 to count theKeys
	set theKey to item i of theKeys
	if getWhat(theKey) is "1" then set end of filteredList to theKey
end repeat
return filteredList
--> RESULT: filteredList = {"cat", "cat2", "cat78", "dog56", "BigCamel_15"}

-- HANDLER TO GET THE VALUE OF KEY BY IT'S STRING REPRESENTATION
on getWhat(what)
	set s to "on run {aRecord}
get " & what & " of aRecord
end"
	run script s with parameters {aRecord}
end getWhat

NOTE: The already well-known AsObjC solution provided by Yvan Koenig is itself excellent in every way. But I wanted users to have a plain AppleScript solution too. With a small bonus - the visual order of the record’s keys in the resulting list is kept.

Thanks to everyone for their responses and scripts :slight_smile: I’m trying them out and reading the discussion on the coding differences. I’ll reply soon.

FWIW, I tested three of the scripts in this thread using Script Geek, and I used the exact record contained in the OP’s post (four check boxes). The “First Run” times were:

Peavine Post 3 - less than a millisecond

Yvan Post 4 - 228 milliseconds

KniazidisR Post 18 - 24 milliseconds

When run twice in succession, the first-run times were:

Peavine Post 3 - less than a millisecond

Yvan Post 4 - 8 milliseconds

KniazidisR Post 18 - 14 milliseconds

I was surprised by the first-run time of the ASObjC script but I ran it many times, always with the same result.