Set record values in repeat loop

I’m self-taught in AppleScript, & hope I’m expressing this clearly.

I’m trying to assign record property values in a repeat loop as part of a larger script, but can’t figure out how to reference the property values consecutively:

global docNamePartsList, dateSetList

set yearFormat to 2
set dateSetList to {component:{|day|:missing value, |month|:missing value, |year|:missing value}, |string|:{"Day (1-31)", "Month (1-12)", "Year (2 or 4 digits)"}, format:{|day|:2, |month|:2, |year|:yearFormat}, limit:{31, 12, null}}

--UNCOMMENT THE VERSION I WANT TO USE
--set dateSetList to my SetNameAndDateFromUserInput()
--set dateSetList to my SetNameAndDateFromUserInput_v2()
set dateSetList to my SetNameAndDateFromUserInput_v3(component of dateSetList)

on SetNameAndDateFromUserInput()
	--WANT TO USE REPEAT LOOP TO SET ITEMS IN LIST TO USER-INPUT VALUES
	local n
	--n IS NUMERICAL REFERENCE TO LIST ITEM I WANT TO ADDRESS
	repeat with n from 1 to 3
		set item n of component of dateSetList to text returned of (display dialog "Enter " & (item n of |string| of dateSetList) default answer "") as number
	end repeat
	return dateSetList
end SetNameAndDateFromUserInput

but when I use numbers (item n of…) it throws an error:

Can’t set item 1 of {|day|:missing value, |month|:missing value, |year|:missing value} to 3

BUT it has no trouble reading a number reference (item n of |string| of dateSetList) for the prompt in the dialog. The dialog displays with the prompt as specified & lets me enter the value. If I skip over the error & move on to the next iteration, the next |string| value displays, as expected.

I thought maybe the nested lists were causing a problem, so I tried jumping through increasingly convoluted hoops; first, breaking up into the individual lists:

on SetNameAndDateFromUserInput_v2()
	--WANT TO USE REPEAT LOOP TO SET ITEMS IN LIST TO USER-INPUT VALUES
	local i, n
	--i IS THE SUB-LIST BEING ADDRESSED
	--n IS NUMERICAL REFERENCE TO SUB-LIST ITEM I WANT TO ADDRESS
	set i to component of dateSetList
	repeat with n from 1 to 3
		set item n of i to text returned of (display dialog "Enter " & (item n of |string| of dateSetList) default answer "") as number
	end repeat
	set component of dateSetList to i
	return dateSetList
end SetNameAndDateFromUserInput_v2

Same result. Then, I tried iterating through list items directly:

on SetNameAndDateFromUserInput_v3(aList)
	--WANT TO USE REPEAT LOOP TO SET ITEMS IN LIST TO USER-INPUT VALUES
	local aList, i, j, n
	--aList IS THE SUB-LIST BEING ADDRESSED, PASSED FROM THE CALLING STATEMENT
	--i IS A HOLDER FOR THE CURRENT STATE OF THE SUB-LIST
	--j IS THE CURRENT ITEM OF LIST i BEING ADDRESSED
	--n IS NUMERICAL REFERENCE TO ITEM I WANT TO ADDRESS
	set i to aList
	set n to 0
	repeat with j in i
		set n to n + 1
		set j to text returned of (display dialog "Enter " & (item n of |string| of dateSetList) default answer "") as number
		set item n of i to j
	end repeat
	return aList
end SetNameAndDateFromUserInput_v3

but even though I’m assigning my repeat variable directly to the list item, the script still interprets it as item # of…, throwing the error; AND each time, in the dialog prompt string, it references a numbered item in another similar sub-list correctly.

This seems inconsistent. How do I get it to identify the list item in the target list by number, as it’s doing w/the similar reference in the dialog prompt string? What am I not getting? Thanks for your help.

Records are unordered collections, and you refer to their values by their labels, not by index.

1 Like

Hello Shane.
Thank you for your response. I understand what you’re saying about name, rather than index, references; but in that case I find it puzzling that in the handler (all versions), the script accepts an index reference to a string variable in a different record.

display dialog "Enter " & (item n of |string| of dateSetList) default answer "") as number --(the |string| sub-record also contains labeled items)

Why does the index reference work there, but not in the “set” reference?

set item n of i... --(where n is a # & i is a list of records)

It seems those 2 references are equivalent & should both trigger the same sort of response, either both returning the item by index or both throwing an error. Is it just an idiosyncracy of AppleScript the index reference works within a display dialog statement but not a set statement?

I attempted to reference the record items by name in v3 of the handler (SetNameAndDateFromUserInput_v3)

local i, n
	--i IS THE SUB-LIST BEING ADDRESSED
	--n IS NUMERICAL REFERENCE TO SUB-LIST ITEM I WANT TO ADDRESS
	set i to component of dateSetList
	repeat with n from 1 to 3
		set item n of i to text returned of (display dialog "Enter " & (item n of |string| of dateSetList) default answer "") as number
	end repeat

I thought that would address the labels, rather than indexes, but the script still reads it as item #

I also tried creating a list of the label names to cycle through, but I get an error, “variable not defined.” If I make the label names as text, it also doesn’t recognize them as labels. Is there a way to iterate through the labels to assign values?

I suspect your i isn’t what you think it is. This works fine:

set x to {{someLabel:1}, {someLabel:3}, {someLabel:6}}
set item 2 of x to 4
return x
1 Like

I think the issue may be confusion over where the records and lists are, and how you address them. Further, just because AppleScript allows you to express a reference to something does not guarantee the reference is correct and thus resolvable at runtime. If you take your initial dateSetList definition:

set yearFormat to 2
set dateSetList to {component:{|day|:missing value, |month|:missing value, |year|:missing value}, |string|:{"Day (1-31)", "Month (1-12)", "Year (2 or 4 digits)"}, format:{|day|:2, |month|:2, |year|:yearFormat}, limit:{31, 12, null}}

This produces a single record with a series of properties, some (|string| and |limit|) containing a list of three scalar values and some ((|component| and |format|) containing a record with its own properties (|day|, |month| and |year|):

{
	component:{
		|day|:missing value, 
		|month|:missing value, 
		|year|:missing value
	}, 
	|string|:{
		"Day (1-31)", 
		"Month (1-12)", 
		"Year (2 or 4 digits)"
	}, 
	format:{
		|day|:2, 
		|month|:2, 
		|year|:2
	}, 
	limit:{
		31, 
		12, 
		null
	}
}

You access the properties of dateSetList using the property of ... form: | format| of dateSetList.

set yearFormat to 2
set dateSetList to {component:{|day|:missing value, |month|:missing value, |year|:missing value}, |string|:{"Day (1-31)", "Month (1-12)", "Year (2 or 4 digits)"}, format:{|day|:2, |month|:2, |year|:yearFormat}, limit:{31, 12, null}}

|format| of dateSetList --> {|day|:2, |month|:2, |year|:2}
|limit| of dateSetList --> {31, 12, null}

For the properties that contain a record, you can use the property of ... form again to get the value you desire:

set yearFormat to 2
set dateSetList to {component:{|day|:missing value, |month|:missing value, |year|:missing value}, |string|:{"Day (1-31)", "Month (1-12)", "Year (2 or 4 digits)"}, format:{|day|:2, |month|:2, |year|:yearFormat}, limit:{31, 12, null}}

|format| of dateSetList --> {|day|:2, |month|:2, |year|:2}
|year| of |format| of dateSetList --> 2

For the properties that contain a list of values, you can use the item n of ... form:

set yearFormat to 2
set dateSetList to {component:{|day|:missing value, |month|:missing value, |year|:missing value}, |string|:{"Day (1-31)", "Month (1-12)", "Year (2 or 4 digits)"}, format:{|day|:2, |month|:2, |year|:yearFormat}, limit:{31, 12, null}}

limit of dateSetList --> {31, 12, null}
item 2 of limit of dateSetList --> 12

Using the property of ... form on a list of values will fail as will using the item n of ... form on a record.

AppleScript does allow you to introspect a list using the count command to get its length. AppleScript does not provide a way to introspect a record. However, you can convert a record to a list to get its values: |format| of dateSetList as list. The problem here is the order of values returned depends on the order of the property declaration:

{aaa:1, bbb:2, ccc:3} as list --> {1, 2, 3}
{aaa:1, ccc:3, bbb:2} as list --> {1, 3, 2}

This isn’t a problem when you are creating the records yourself and you know the order of properties. But if you are receiving the records from some external source or are not standardized in how you create your records, the ordering of values can be unpredictable.

Finally, the item n of ... form can be combined with as list:

item 2 of ({aaa:1, bbb:2, ccc:3} as list) --> 2

NOTE: the parenthesis are crucial because the item n of ... operation has a higher priority than the ... as list operation.

1 Like