Applescript – Delimit records and lists

Hi is there a way to get all the records out of a list tab delimited?

set mylist to {OrderID:“55555”, CustomerID:“Customer 55555”, CustomerName:“Mr Robot”}

eg. “55555Customer 55555Mr Robot”

many thanks

Shane

Hi. Yes”easily.

set text item delimiters to tab
{OrderID:"55555", CustomerID:"Customer 55555", CustomerName:"Mr Robot"}'s items as text

Marc’s answer works . sometimes.

In a record as the original one, the order of the different items is not guaranteed.

If the script receive the record in an alternate order Marc’s code will return a wrong value.


# Record in an alternate order
set mylist to {CustomerID:"Customer 55555", OrderID:"55555", CustomerName:"Mr Robot"}

set oTids to AppleScript's text item delimiters
set AppleScript's text item delimiters to tab
# You will get the string CustomerID value ⇥ OrderID value ⇥ CustomerNameValue
set theString to mylist's items as text # Marc's result
set AppleScript's text item delimiters to oTids
log theString (*Customer 55555	55555	Mr Robot*)

set mylist to {CustomerID:"Customer 55555", OrderID:"55555", CustomerName:"Mr Robot"}
set l to {mylist's OrderID, mylist's CustomerID, mylist's CustomerName}
set {oTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, tab}
set theString to l as text
set AppleScript's text item delimiters to oTids

# With this code we are sure that the returned string is OrderID value ⇥ CustomerID value ⇥ CustomerNameValue
theString
--> "55555	Customer 55555	Mr Robot" 

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) vendredi 29 janvier 2016 19:21:32

Your “list” is actually record. It has labelled properties with values.

A list contains items ” ie. just the values:

{“55555”, “Customer 55555”, “Mr Robot”}

Knowing the difference will make Yvan’s correction easier to understand.

Dealing with records in AppleScript is a royal PITA, very limiting, and frustrating.
(of course, it may all be due to my limitations. :confused: )

If you are open to using JavaScript for Automation (JXA), you will find JavaScript can handle this type of task easily with a lot more flexibility.

Let me know if you are interested, and I’ll gen up an example.

They’re certainly very limited.

Nonsense. The issue of trying to treat key-based collection as some kind of ordered collection is common to pretty much every language.

Some things to do with records/dictionaries are much easier in most languages, but this particular aspect isn’t one of them.

Not entirely. JXA, or better said JavaScript, doesn’t have a associative arrays or dictionaries but uses an object with properties to simulate a dictionary. However there is no guarantee that the enumerator will get the value in the same order every time or in the same order as it is created. So even if JXA has an enumerator for objects, which completely lacks in AppleScript, it is not safe.

[format]var record = {‘key1’:1, ‘key2’:2, ‘key3’:3};

for (key in record)
{
console.log(record[key]);
}
[/format]

Thanks everyone, I’ll see these as records now.

I’ve gone with Marc’s script but changed it up a bit.

set text item delimiters to tab
set myList to {OrderID:"55555", CustomerID:"Customer 55555", CustomerName:"Mr Robot"}
log every item of myList as text

You haven’t understood Yvan’s post. The order of the properties in a record isn’t guaranteed. If you don’t care which values are which, Marc’s script’s fine. Otherwise, you should get the values explicitly by label and then arrange them in the order you want them.

Maybe he didn’t misunderstand. The order of any list is never guaranteed and may need to be sorted, but I operate on the assumption that, where a record list exists, the person manipulating it is the likely author and should’ve initially put things in the desired order, rather than having to retroactively adjust key:value pairs. You people thinking the opposite are TID-preserving, verbose-coding crazies. :smiley:

That’s not the point marc. The problem is that a normal list or array will have an order the values are stored; it’s index based. So set item 1 of theList to theValue is certain that item 1 always contains theValue unless overwritten. So the order of every list is actually guaranteed!

When using a key value pair and using set theKey of theRecord to theValue I have no idea what kind of index is associated with that key. And because it has no index, the keys can be retrieved in a different order than assigned. Especially when using AppleEvents, the order of user defined keys are preserved and bundled because all user defined key value pairs are stored in a single list and not as separate values. AppleScript’s internal does handle those kind of records differently.

display dialog {a:1, name:2, b:3, length:4}

The code above will return in an error but look at the order of the record described in the error message, the order of the keys has changed.

So the real question in this topic is, is the order of each item of the record important or not; does OrderID needs to be the first item in the tab delimited list? If not lowjackson can use your code, if it does he needs to use Yvan’s code.

I see that Yvan’s code explicitly orders the list by calling the key, but the OP’s code sample doesn’t appear to suffer from the issue being corrected. Unless I’m misunderstanding, the dialog example fails due to keys haphazardly mixing non-reserved with reserved words. Only one type should have been used or the keys should have been piped; this prevents the necessity of manually reordering and retyping.


display dialog {size:1, name:2, length:3}'s items as text --reserved
display dialog {sizeID:4, nameID:5, lengthID:6}'s items as text --non
display dialog {a:7, b:8, |length|:9}'s items as text --piped

From my point of view you miss the point.

One well known example is the record returned by display dialog “Hello world” default answer “Betelgeuse”
For years, according to sample codes delivered by Apple, some users worked with :

set aRecord to display dialog "Hello world" default answer "Betelgeuse"
log result (*text returned:Betelgeuse, button returned:OK*)
set aList to aRecord as list
log result (*Betelgeuse, OK*)
set theAnswer to item 1 of aList
--> "Betelgeuse"[/Applescriptt]
and they got the wanted result : "Betelgeuse"

Alas, some years ago, when Apple delivered 10.9 or 10.10, the record was returned with the reversed order.
Running the old script gave :

set aRecord to display dialog “Hello world” default answer “Betelgeuse”
log result (button returned:OK, text returned:Betelgeuse)
set aList to aRecord as list
log result (OK, Betelgeuse)
set theAnswer to item 1 of aList
→ “OK”



which fooled a lot of users.

Those taking care of records behavior used 

set aRecord to display dialog “Hello world” default answer “Betelgeuse”
log result (button returned:OK, text returned:Betelgeuse)
set aList to {aRecord’s text returned, aRecord’s button returned}
→ {“Betelgeuse”, “OK”}
set theString to item 1 of aList


and their code didn't suffer when the change was introduced.

Some others used an alternate scheme which prove to be robust too 

set aRecord to display dialog “Hello world” default answer “Betelgeuse”
log result (button returned:OK, text returned:Betelgeuse)
tell aRecord to set {theString, theButton} to {text returned, button returned}
log result (Betelgeuse, OK)
theString
→ “Betelgeuse”



All that is clear for those which took care to read AppleScript Language Guide which states :
record
An [b]unordered[/b] collection of labeled properties. The only AppleScript classes that support user-defined properties are record and script.
.
Two records are equal if they both contain the same collection of properties and if the values of properties with the same label are equal. They are not equal if the records contain different collections of properties, or if the values of properties with the same label are not equal. [b]The order in which properties are listed does not affect equality[/b].

This said, you are free to play with matches but don't cry if you burn your fingers.

In my first message, the treatment of item delimiters was not related to the ordering of values.
It's a completely different problem. Some users don't pay attention to the original delimiters, some other pay attention. 
My advice is that there is a sufficient count of chances to generate odd behaviors when using AppleScript to do our best to eliminate those which we may drop.

Yvan KOENIG running El Capitan 10.11.3 in French (VALLAURIS, France) dimanche 31 janvier 2016 10:41:24

What’s a record list?

You’re also assuming that the OP’s an experienced scripter, which isn’t what his query suggests.

:slight_smile:

Yeah. I must admit I sometimes labour under the delusion that this is a help forum and that many of the people who ask for help here are actually interested in learning from the replies they receive. If what they learn is wrong ” even if it happens to work in the narrow context of their query ” then they haven’t really been helped. They’ll just go on to apply the bad advice in other scripts and one day it’ll bite them in the foot, forcing them perhaps to come back and ask why it doesn’t work. Before then ” who knows? ” they may even propagate the falsehood themselves, posting this cool script they got from MacScripter on other fora or in their own blogs. This is the Internet, after all. They probably won’t be the only people reading the original thread either.

It is sometimes necessary in AppleScript to use hacks or dodgy practices to get things done which can’t be achieved any other way, but they should alway be published with health warnings so that users immediately know the probable cause when things go wrong. However, such measures aren’t necessary in the present case.

For the ” ah ” record, the AppleScript Language Guide’s very first utterance on the subject of records is: “A record is an unordered collection of labeled properties.” This doesn’t imply that if you type a record in a particular order, the order will be preserved when the “items” (ouch) are extracted or when the record’s coerced to list.

Just so we are clear, my little jibe was in jest; it certainly wasn’t intended to derail the learning purpose of the forum. From my point of view, the cautions being given were not applicable to the actual situation, and too much information”especially when not supported by clear examples of pitfalls” can confuse just as easily as “dodgy practices.” :wink:

Yvan’s example in post 13 is a pitfall, but it’s inapplicable, because those keys aren’t user-generated and order can’t be anticipated; clearly there is a need to reference the key in that situation, rather than asking to retrieve “item 1” from an indexless result. The language guide’s statement that records are “unordered collections of labeled properties” can be illustrated:

{size:1, name:2, length:3} = {name:2, length:3, size:1}

This is obviously true, but unordered equality doesn’t imply that, if a user creates a record in a specific order, it results in total chaos.

OK, I can see that I am in a group of AppleScript experts that don’t see much value in JavaScript or JXA. So I’ll quietly bow out of this discussion. I will say that I have found some things that can be done easily in JavaScript that are impossible in AppleScript, and leave it at that.

Good luck to you all.

And that’s true, but not really relevant in this case.

(FWIW, JXA’s biggest problem is that it’s designed around Cocoa scripting, and a lot of the older and most scriptable apps don’t use Cocoa scripting, so it doesn’t play well with them.)

No, JXA can do things AppleScript can’t (like I said in the part you didn’t quote). I posted an example code to be clear we’re talking about the same thing, unless you knew something I didn’t. From my experience the object’s property enumerator is not ordered and therefore in this particular case JavaScript doesn’t have an better or easier solution as you implied; In my opinion they are equally good. In other words, to get the items you still need to explicitly get each item by it’s key. It is certainly not an AppleScript vs. JavaScript thing, it’s just a general programming problem.

I still prefer you give us that example than leaving this discussion.

For the sake of completeness this is the AppleScriptObjC solution


use framework "Foundation"

set mylist to {OrderID:"55555", CustomerID:"Customer 55555", CustomerName:"Mr Robot"}
set myDict to (current application's NSDictionary's dictionaryWithDictionary:mylist)
set theResult to (myDict's allValues()'s componentsJoinedByString:"	") as text -- the string between the double quotes is "backslash tab"

Interestingly it keeps always the original “order” of the AppleScript record, although the record is (supposed to be) unordered.

An NSDictionary is unordered as well and often gets values in a different order than created.