Problem with var and records in a property

property cl : {A5:“100”, A6:“100”, A3:“B”, L1:“U”, D1:“V”}

– I want to check the value of, say, A5 - this works:
return A5 of cl
→ “100”

– But I need to look up the value from a var, so say the var contains A5:
set myVar to “A5”
return myVar of cl
→ Can’t get myVar of {A5:“100”, A6:“100”, A3:“B”, L1:“U”, D1:“V”}

– How can i Make this work? Or any other ideas? Please dont ask me
– to loop thru the lists, they are huge!

set myVar to “A5” assigns the string “A5” to the variable myVar.

You want the value stored at the location represented by the label A5 in your record.

This will do the trick:

set myVar to A5 of cl
→ 100

HTH,

Ethan

Not sure how to use the property thing

but could this work for you?

property cl : {A5:“100”, A6:“100”, A3:“B”, L1:“U”, D1:“V”}
set {myVar1, myvar2, myvar3, myvar4, myvar5} to {1, 2, 3, 4, 5}
set {old_TIDs, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, “,”}
set the_list to the text items of cl as list

set AppleScript’s text item delimiters to old_TIDs
return item myVar1 of the_list
– I want to check the value of, say, A5 - this works:
–return A5 of cl
→ “100”

– But I need to look up the value from a var, so say the var contains A5:

→ Can’t get myVar of {A5:“100”, A6:“100”, A3:“B”, L1:“U”, D1:“V”}

– How can i Make this work? Or any other ideas? Please dont ask me
– to loop thru the lists, they are huge!

First, some AppleScript terminology:

{A5:“100”, A6:“100”, A3:“B”, L1:“U”, D1:“V”} is a record.
A5:“100” is a field in that record.
A5 is the field’s label.
“100” is the field’s value.

Since a label is in effect a keyword - indicating an element of a record - it can’t be held in a variable, either as a label or in string form. It’s therefore best not to write scripts in a way that depends on this being possible. :wink:

However, if it’s unavoidable, there is a cheat you can use:

property cl : {A5:"100", A6:"100", A3:"B", L1:"U", D1:"V"}

on getValueUsingLabelString(theRecord, labelString)
  try
    -- Some nonsense that generates an error message
    theRecord as integer
  on error errMsg
    -- errMsg is "Can't make {A5:"100", A6:"100", A3:"B", L1:"U", D1:"V"} into a integer."
    
    set ASline to labelString & " of " & text 12 thru -17 of errMsg
    -- ASline is "A5 of {A5:"100", A6:"100", A3:"B", L1:"U"}"
    
    return (run script ASline)
  end try
end getValueUsingLabelString

set myVar to "A5"
getValueUsingLabelString(cl, myVar)
--> "100"

But this is only good for reading fields. If you want to set them, you’ll need another cheat - which has a rather inportant proviso. Record labels are stored internally as lower-case strings. Normally this doesn’t make any difference, but the cheat below expects the supplied label string to be lower case, otherwise it creates a barred version of the label - eg. |A5| instead of just A5. These are not treated as the same label. So either the label strings must always be lower case, or they must be converted during the cheat. Here, I’ve used ‘lowercase’ from the Satimage OSAX:

property cl : {A5:"100", A6:"100", A3:"B", L1:"U", D1:"V"}

on setValueUsingLabelString(theRecord, labelString, thevalue)
  script o
    -- 'lowercase' requires the Satimage OSAX
    {«class usrf»:{lowercase labelString, thevalue}}
  end script
  
  -- Create a one-field record with the required label and value
  -- and concatenate the original record to it
  return (run script the result) & theRecord
end setValueUsingLabelString

set myVar to "A5"
set cl to setValueUsingLabelString(cl, myVar, "Hello!")
--> {A5:"Hello!", A6:"100", A3:"B", L1:"U", D1:"V"}
2 Likes

Hi Nigel and all :slight_smile:

Really very clever method Nigel. :smiley:

It is just necessary to think of adapting it according to the language in service in the system, because in French, for example, i am the following result:
“Impossible de désigner {A5:“100”, A6:“100”, A3:“B”, L1:“U”, D1:“V”} comme integer.”

We sought a long time, in the French mailing list of AppleScript, an effective method allowing dynamic management of the variables… but, unfortunately, it seems to me that this is not really possible. However, we found some solutions to dynamically manage a “records” lists (moreover, I have just finalized a complete version of this method, that I propose to you to discover and test in the “beta testing forum”)…

Well, with regard to this topic and the problem of “jocke66”:

Here a small suggestion (this is a part of the method which I evoked):

--[Script Choose item in record with dialog]
property ListRecord : {A5:"100", A6:"100", A3:"B", L1:"U", D1:"V"}
property myLabel : "A5"

set myLabel to text returned of (display dialog ¬
	"Show value of this variable :" default answer myLabel with icon 1)

set myScript to "on run theRecord
return " & myLabel & " of (item 1 of theRecord)
end run"

try
	set myValue to (run script myScript with parameters ListRecord)
	display dialog "Label: " & myLabel & return & "Value: " & myValue with icon 1
on error
	display dialog "The required label does not exist..." & (beep) with icon 0
end try
--[/Script]

In this first version it is necessary to write the name of the label to be consulted, which is not the best way, in my opinion…

Here a second proposal allowing for choice of the label to be consulted in a list (which it is necessary to build as a preliminary):

--[Script Choose item in record with list]
property ListRecord : {A5:"100", A6:"100", A3:"B", L1:"U", D1:"V"}
property ListLabels : {"A5", "A6", "A3", "L1", "D1"}
property myLabel : "A5"

set myChoice to (choose from list ListLabels)
if myChoice is not false then set myLabel to (item 1 of myChoice) as text

set myScript to "on run theRecord
return " & myLabel & " of (item 1 of theRecord)
end run"

set myValue to (run script myScript with parameters ListRecord)
display dialog "Label:  " & myLabel & return & "Value:  " & myValue with icon 1
--[/Script]

It is an enthralling study to seek solutions with this type of problems… :wink:

Hi, Fredo. :slight_smile:

Thanks. I wish I could claim to have invented the error message idea. I think it may have been Jeff Baumann.

Ah, oui! J’oubliais…

on getValueUsingLabelString(theRecord, labelString)
  try
    theRecord as integer
  on error errMsg
    -- set errMsg to "Impossible de désigner {A5:"100", A6:"100", A3:"B", L1:"U", D1:"V"} comme integer."

    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "{"
    set recordStr to "{" & text from text item 2 to -1 of errMsg
    set AppleScript's text item delimiters to "}"
    set recordStr to text 1 thru text item -2 of recordStr & "}"
    set AppleScript's text item delimiters to astid
    set ASline to labelString & " of " & recordStr
    return (run script ASline)
  end try
end getValueUsingLabelString

Brilliant! The relevant parts make a much simpler handler than mine - and just as effective. (And that’s the first time I’ve seen (beep) concatenated into a string!) :slight_smile:

By the way, I asserted in my previous post that the items in a record are called “fields”. Double-checking with the AppleScript Language Guide, I see they’re called “properties” there. It’s these properties that have “labels” and “values”.

I’ve never seen

either. Not sure why it works but it’s cool!

Jon

That is a neat tip: You can also use the “say” command in the dialog to say something…

http://scriptbuilders.net


[This script was automatically tagged for color coded syntax by Script to Markup Code]

Hi,

Not sure if this was covered but you might try getting rid of records, labels, and variables altogether and just use the strings as varibles. This makes it more dynamic. Something like this idea:

script Myvars
property var_list : {{“x”, missing value}, {“y”, missing value}}
property var_count : count var_list

on SetVar(the_var, the_val)
set i to 1 – var_list has at least one item
repeat
try
set sub_list to item i of var_list
if first item of sub_list is the_var then
set item i of var_list to {the_var, the_val}
exit repeat
end if
set i to i + 1
on error
exit repeat
end try
end repeat
if i > var_count then – make new variable
set end of var_list to {the_var, the_val}
else
return the_val
end if
end SetVar

on GetVar(the_var)
set the_val to missing value
repeat with this_sub in var_list
if first item of this_sub is the_var then
set the_val to second item of this_sub
exit repeat
end if
end repeat
return the_val
end GetVar
end script
---------- examples
SetVar(“y”, “hi”) of Myvars
SetVar(“z”, “bye”) of Myvars
{GetVar(“y”) of Myvars, var_list of Myvars}

Not sure if this was covered yet. And I almost forgot, you might want to add a routine to remove a variable which depends on your thinking.

Almost forgot this also. The examples could be rewritten in a tell block. Something like this:

tell Myvars
SetVar(“y”, “hi”)
SetVar(“z”, “bye”)
{GetVar(“y”), var_list of it}
end tell

gl,

I do something very similar but instead of lists of lists, I just create two paired lists (and the values of these lists can be anything, strings, numbers, variables, etc.), one with the “labels” and the other with the values and then routines to pull out the match or change the value of the match:

Jon


[This script was automatically tagged for color coded syntax by Convert Script to Markup Code]

Hi :slight_smile:

Thanks :smiley:

Yes, it is really very practical… :slight_smile:
I found this syntax while exploring, a little, the possibilities that AppleScript offers to carry out actions on only one line of code…
I found two methods which work rather well (I did not test their speed of execution yet):

  • By concatenation:
tell application "Finder" to display dialog "" & (activate) & (beep) & (name of (choose file)) with icon 1
  • By overlap:
tell application "Finder" to display dialog "" & (name of (choose file (beep (activate)))) with icon 1

Yes… indeed, thank you Nigel for thise precision… :slight_smile:

Hi,

Jonn8, I tried that before but don’t like working wiht 2 seperate lists. That’s too much thinking for me :-).

Anyway, I eliminated some unnecessary stuff from the other script and added error for undefined “variable”:

---------- scripts
script Myvars
property var_list : {}
– clear var_list
on InitVars()
set var_list to {}
return var_list
end InitVars
– sets a variable to value or makes new variable
on SetVar(the_var, the_val)
set i to 1
repeat
try
set sub_list to item i of var_list
if first item of sub_list is the_var then
set item i of var_list to {the_var, the_val}
exit repeat
end if
set i to i + 1
on error – list was exhausted
set end of var_list to {the_var, the_val}
end try
end repeat
return the_val
end SetVar
– returns value of the variable or undefined error
on GetVar(the_var)
repeat with this_sub in var_list
if first item of this_sub is the_var then
set the_val to second item of this_sub
exit repeat
end if
end repeat
try
return the_val
on error – the_val is undefined
error number -2753 from the_var
end try
end GetVar
end script
---------- end scripts
on run
InitVars() of Myvars
tell Myvars
SetVar(“y”, “hi”)
SetVar(“z”, “bye”)
– GetVar(“err”) – now returns undefined
end tell
var_list of Myvars
end run

Also, thought that initializing the var list to {} is better and more how it should work.

gl,

Wow! :slight_smile: That really is bizarre. But at least it’s understandable. The inner commands are executed first - in principle, to pass back results to the next layers out. ‘Activate’ and ‘beep’ don’t return results, but then they’re not required in this particular sequence.

The real oddity is the concatenation of a result-less command into a string, which should require a result. It seems that the implicit coercion of the non-result to string produces an empty string. This can be shown explicitly:

(beep) as string
--> ""

It also works for coercion to list:

(beep) as list
--> {}

Although the coercion to string works fine with all the AppleScript versions I have, I think it’s probably exploiting a bug. :frowning: With AS 1.3.7 (OS 8.6), the coercion to to list - although it produces a result in Script Editor’s Result window - doesn’t produce a result that’s visible to the script. With AS 1.8.3 and 1.9.1 (OS 9.2.2 and 10.2.8 respectively), the coercion to list is available to the script - but it’s not an empty list: it’s a list containing no result!

set fred to (beep) as list
--> {}
set end of fred to Tuesday
fred
--> {, Tuesday}
count fred
--> 2

I’ll ask about this in AS-Users in the morning (if no-one beats me to it).

Hi Jon and Kel :slight_smile:

There is a possibility to build a record list starting from two lists.
The first list represents the labels, and the second is a list of the values.
Here an example:

--[Script Lists to Records]
property ListLabels : {"lastname", "firstname", "country"}
property ListValues : {{"Aznavour", "Charles", "France"}, {"Sinatra", "Frank", "Unated States"}}

set theRecord to my SubListsToRecords(ListLabels, ListValues)
-->{{lastname:"Aznavour", firstname:"Charles", country:"France"}, {lastname:"Sinatra", firstname:"Frank", country:"Unated States"}}

return {firstname, lastname, country} of item 2 of theRecord
-->{"Frank", "Sinatra", "Unated States"}

on SubListsToRecords(List1, List2)
	set TextScript to ""
	repeat with ItemList2 in List2
		set ListText to ""
		repeat with Loop from 1 to (count items of List1)
			set Item1 to item Loop of List1
			set Item2 to item Loop of ItemList2
			set ListText to ListText & Item1 & ":"" & Item2 & "", "
		end repeat
		set TextScript to TextScript & {"{" & text 1 thru -3 of ListText & "}, "}
	end repeat
	set TheScript to ("return {" & (text 1 thru -3 of TextScript) & "}")
	return run script TheScript
end SubListsToRecords
--[/Script]

:wink:

Hi Nigel :slight_smile:

Thanks Nigel… very interesting and instructive your tests… :slight_smile:

In this series of “bizarre” things, it should be noted that it is completely possible to use a list with commands, for example:

tell application "Finder" to return {item 3, item 5} of ¬
	{"" & (activate), "" & (beep), "" & (choose folder), "" & (beep), name of (choose file)} 
-->{"OsX:Applications:", "test.txt"} 

:shock: :!: :!: :!:

Yes, :idea: excellent initiative… Please, keep us informed :slight_smile:

Hi Fredo,

Thanks for bringing this up using ‘run script’ to create a record. It seems that everytime this problem comes up I go through the same motions. The same problem always arises. If you create a record dynamically from say user input of text, you can’t use the record anyway because I have never found some way to get a field value through its label. For instance, in your script, you create the labels from text and get the values through labels:

return {firstname, lastname, country} of item 2 of theRecord

Have you found some way to get say lastname without using labels. I think this was discussed above in the other posts but this is the problem with records.

Thanks,

Good evening kel:slight_smile:

Forgiveness for this late answer (much work today)…

Excuse me, but I do not understand your question very well…

Do you want to know the value of one item, in a record, without using the label which indicates it?
In other words, you wish to know a value, only by indicating its place in the list record… it is correct?

If it is the case, you can do it, by converting beforehand the record to a simple list of values.
For example:

set theRecord to {lastname:"Sinatra", firstname:"Frank", country:"Unated States"}

set theList to theRecord as list -->Coerce the record to a list

set thefirstname to item 2 of theList
-->"Frank"

If it is not what you seek, could you a little better specify your question?
I would try to answer it as well as possible of my competences.
Thanks :slight_smile:

I think kel wants to use strings instead of labels to access record properties. If so, Fredo’s first contribution to this thread - and mine - offer solutions to this.

Oooh, no! :shock: A property’s position in a record is not fixed or relevant. The point of using records is that properties are accessed by label, not position. When you coerce a record to list, the positions of the items in the list reflect the order of the record at the moment of coercion - which is not necessarily the order in which the record was originally defined.

Hi,

Originally, what I was saying is that it’s better to use the list of lists to store dynamic variables instead of in records where the variables are the labels and the values are the field values. Then, I’m saying that changing the list to record has no purpose. If you coerce the record to list, then you still need an index to the list item. Just having the list has no purpose either. Say you have input of a list like this:

{{“x”,“1”},{“y”,“2”},{“z”,“3”}}

(note: with this it is easy to add a new “variable”)

Now you make a record out of this:

{x:“1”,y:“2”,z:“3”}

And say this record is the value of the variable the_record. Now you want to get:

y of the_record

You don’t have the label ‘y’ in your script. Right, the record is not ordered and furthermore you need an index if you coerce it to list. On top of this, say you wanted to add a field (another “variable”). So you coerce your record to list. You still need the index and the original “variable” in string form to create a new list and create a new record to add a new field!

Every so often someone posts this same problem. When you look at the overall purpose, you can see that it is best to keep the input “variables” as strings.

BTW, Fredo. Nice work on the list to record script. I like the way you thought out making the text for the ‘run script’. Thanks a lot. It was very informative.

gl,

Hi, Fredo et alia.

I promised to ask on the AS Users list about:

display dialog "The required label does not exist..." & (beep) with icon 0

… which I thought might be the exploitation of a bug, and:

tell application "Finder" to display dialog "" & (name of (choose file (beep (activate)))) with icon 1

… which I though probably wasn’t. At first, I thought no-one was going to reply. But then Arthur Knapp provided this explanation of what was being coerced to string when (beep) produced no result to coerce:

And here’s the official line from Chris Nebel:

It looks as though Fredo’s techniques may continue to work in the future… :slight_smile: