Saturday, September 24, 2022

#1 2021-01-23 06:46:12 pm

wayland
Member
From:: Nha Trang
Registered: 2020-05-13
Posts: 76

convert a list to a record

I have this list:

Applescript:


set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

How would I convert this into a record?

It should end up looking like:

{adam: "604", eddie: "601", susie: "602", etc.}

Last edited by wayland (2021-01-23 06:59:52 pm)

Offline

 

#2 2021-01-23 10:47:27 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2522

Re: convert a list to a record

Hi,

One known technique is this:

Applescript:


set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

-- convert the original list to raw list {"Adam", "604", "Eddie", "601", "Susie", "602" ,...}
set rawList to {}
repeat with theItem in theList
   set end of rawList to item 1 of theItem
   set end of rawList to item 2 of theItem
end repeat

-- convert to rawRecord
set rawRecord to {«class usrf»:rawList}

-- A script which forces coercion between AppleEvent and AppleScript later
script x
   on run argv
       return item 1 of argv
   end run
end script

-- final result
set theRecord to run script x with parameters {rawRecord}

Last edited by KniazidisR (2021-01-23 11:21:40 pm)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 14.1
Ram: 4 GB

Offline

 

#3 2021-01-23 11:13:24 pm

bmose
Member
From:: Massachusetts
Registered: 2006-01-03
Posts: 381

Re: convert a list to a record

Here is an ASObjC NSMutableDictionary solution:

Applescript:


use framework "Foundation"
use scripting additions
property || : current application

set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

set theDict to (||'s NSMutableDictionary)'s |dictionary|()
repeat with currPair in theList
   set {currKey, currValue} to currPair's contents
   (theDict's setObject:currValue forKey:currKey)
end repeat
set theRecord to theDict as record

theRecord --> {Ive:"605", Will:"607", Steve:"603", Eddie:"601", Ben:"608", Susie:"602", Tim:"603", Adam:"604", Dave:"607", Jimmy:609}

Here is a System Events Property List solution:

Applescript:


set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

tell application "System Events"
   set plistFile to make new property list file with properties {contents:(make new property list item with properties {kind:record}), name:"/tmp/MyPlistFile.plist"}
   repeat with currPair in theList
       set {currKey, currValue} to currPair's contents
       make new property list item at end of plistFile's property list items with properties {name:currKey, value:currValue}
   end repeat
   set theRecord to property list file "/tmp/MyPlistFile.plist"'s value
end tell

theRecord --> {Tim:"603", Will:"607", Steve:"603", Dave:"607", Adam:"604", Ben:"608", Eddie:"601", Ive:"605", Jimmy:609, Susie:"602"}

Incidentally, I assume that the integer value for "Jimmy" should be a text string?  In any case, I left it as an integer to show that a value's class will be retained in the newly formed record with either of the above techniques.

Offline

 

#4 2021-01-23 11:43:33 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2522

Re: convert a list to a record

Hi bmose,

I guessed that there are other techniques, and thanks for them, although I'll leave the first for myself.

I compared 3 scripts by speed. As always when I see new alternatives. The result is this: my script (which was invented by another person, DJ Bazzie Wazzie) is 2 times faster than your AsObjC-solution and at least 20 times faster than the System Events-solution.
[/applescript]

Last edited by KniazidisR (2021-01-24 12:38:12 am)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 14.1
Ram: 4 GB

Offline

 

#5 2021-01-24 12:12:16 am

bmose
Member
From:: Massachusetts
Registered: 2006-01-03
Posts: 381

Re: convert a list to a record

KniazidisR,

Yours and DJ's "{«class usrf»:rawList}" method is quite creative.  I hadn't seen it before.  I tested it with other value types (integer, real, boolean, date, list, record), and it worked well with those value types as well.

Many ways to skin this cat!

Last edited by bmose (2021-01-24 12:17:56 am)

Offline

 

#6 2021-01-24 12:45:01 am

bmose
Member
From:: Massachusetts
Registered: 2006-01-03
Posts: 381

Re: convert a list to a record

For completeness, here is a serialization method that can handle values of virtually any class:

Applescript:


   script util
       on textValue(theValue)
           try
               || of {theValue}
           on error m
               set tid to AppleScript's text item delimiters
               try
                   set AppleScript's text item delimiters to "{"
                   set m to m's text items 2 thru -1 as text
                   set AppleScript's text item delimiters to "}"
                   set theText to m's text items 1 thru -2 as text
               end try
               set AppleScript's text item delimiters to tid
           end try
           return theText
       end textValue
   end script
   
   set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}
   
   set serializedRecord to ""
   repeat with currPair in theList
       set {currKey, currValue} to currPair's contents
       if serializedRecord ≠ "" then set serializedRecord to serializedRecord & ", "
       set serializedRecord to serializedRecord & currKey & ":" & util's textValue(currValue)
   end repeat
   set theRecord to run script ("{" & serializedRecord & "}")

   theRecord --> {Adam:"604", Eddie:"601", Susie:"602", Tim:"603", Steve:"603", Ben:"608", Dave:"607", Jimmy:609, Ive:"605", Will:"607"}

KniazidisR wrote:

I compared 3 scripts by speed. As always when I see new alternatives. The result is this: my script (which was invented by another person, DJ Bazzie Wazzie) is 2 times faster than your AsObjC-solution and at least 20 times faster than the System Events-solution.

I ran speed tests with 1000 repetitions per method and got slightly different results:

ASObjC method - 0.0007 seconds
«class usrf» method - 0.0009 seconds
System Events method - 0.0025 seconds
serialized record method (this post) - 0.0918 seconds

By these speed tests, the ASObjC and «class usrf» methods are very close to each other in speed, the System Events method is 3-4 times slower, and the serialized record method is quite slow (relatively speaking.)

Last edited by bmose (2021-01-24 12:50:16 am)

Offline

 

#7 2021-01-24 03:40:53 am

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2522

Re: convert a list to a record

bmose wrote:

I ran speed tests with 1000 repetitions per method and got slightly different results:

ASObjC method - 0.0007 seconds
«class usrf» method - 0.0009 seconds
System Events method - 0.0025 seconds
serialized record method (this post) - 0.0918 seconds


On first testing (using Script Geek of Shane Stanley) I tested with 5 repetitions. Now, the results with 1000 repetitions is this:

«class usrf» method - 0.018 seconds
ASObjC method ------- 0.061 seconds

Using a reference to for your property (property || : a reference to current application) I got:

«class usrf» method - 0.012 seconds
ASObjC method ------- 0.024 seconds

I use "Run both". That is, when completion of one script is shorter, the completion of other script is shorter too. But, important is only the result in compare.

Your serialization method that can handle values of virtually any class, is great.

Last edited by KniazidisR (2021-01-24 04:00:55 am)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 14.1
Ram: 4 GB

Offline

 

#8 2021-01-24 04:00:11 am

Fredrik71
Member
Registered: 2019-10-23
Posts: 964

Re: convert a list to a record

KniazidisR wrote:

Hi,

One known technique is this:

Applescript:


set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

-- convert the original list to raw list {"Adam", "604", "Eddie", "601", "Susie", "602" ,...}
set rawList to {}
repeat with theItem in theList
   set end of rawList to item 1 of theItem
   set end of rawList to item 2 of theItem
end repeat

-- convert to rawRecord
set rawRecord to {«class usrf»:rawList}

-- A script which forces coercion between AppleEvent and AppleScript later
script x
   on run argv
       return item 1 of argv
   end run
end script

-- final result
set theRecord to run script x with parameters {rawRecord}


Interesting I have seen that before, it could be useful handler.

Applescript:

on listToRecord(theList)
   set rawList to {}
   repeat with theItem in theList
       set end of rawList to item 1 of theItem
       set end of rawList to item 2 of theItem
   end repeat
   script x
       on run argv
           return item 1 of argv
       end run
   end script
   return run script x with parameters {{«class usrf»:rawList}}
end listToRecord

Nigels version in ASobjC

Applescript:

on listToRecord:theList
   set theKeys to {}
   set theValues to {}
   repeat with currPair in theList
       set {end of theKeys, end of theValues} to currPair's contents
   end repeat
   return (current application's NSDictionary's dictionaryWithObjects:theValues forKeys:theKeys) as record
end listToRecord:

Nigels version was faster on my machine compare to vanilla AppleScript version.

Last edited by Fredrik71 (2021-01-24 04:15:39 am)


if you are the expert, who will you call if its not your imagination.

Offline

 

#9 2021-01-24 04:00:44 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5563

Re: convert a list to a record

Here's a faster variation of the ASObjC method you may like to try. Most of the work's done in vanilla AppleScript:

Applescript:


use framework "Foundation"
use scripting additions
property || : current application

set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

set theKeys to {}
set theValues to {}
repeat with currPair in theList
   set {end of theKeys, end of theValues} to currPair's contents
end repeat
set theRecord to (||'s NSDictionary's dictionaryWithObjects:theValues forKeys:theKeys) as record


NG

Offline

 

#10 2021-01-24 04:10:30 am

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2522

Re: convert a list to a record

Nigel Garvey wrote:

Here's a faster variation of the ASObjC method you may like to try. Most of the work's done in vanilla AppleScript:


Well, Nigel, as I see you're just an expert in improving the speed of scripts:
With 1000 repetitions:

AsObjC method: ----- 0.006 sec
«class usrf» method - 0.012 sec

I searched little here to improve plain AppleScript solution. It seems, I found it:

Applescript:


set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}

set rawList to a reference to {}
repeat with currPair in theList
   tell rawList to set {end, end} to contents of currPair
end repeat

-- Create a record who is similar to records containing only user defined keys in AppleEvents
set theRecord to «class seld» of (record {«class usrf»:rawList} as record)

With 1000 repetitions:

AsObjC method: ----- 0.006 sec
«class usrf» method - 0.006 sec

Last edited by KniazidisR (2021-01-24 06:28:19 am)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 14.1
Ram: 4 GB

Offline

 

#11 2021-01-24 07:01:43 am

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2522

Re: convert a list to a record

For completeness, here is a very effective plain-AppleScript solution, when the key names (text class) and the values (any) is given as 2 separate lists:

Applescript:


script o
   property theKeys : {"The Condition", "This Script Runnig Date", "Hi, Susiehi", "Tim", "the Path", "Ben"}
   property theValues : {true, current date, "hello", 1, path to me, "joke"}
end script

-- Create a list containing keys subsequently followed by it's associated value
set rawList to a reference to {}
repeat with i from 1 to count o's theKeys
   tell rawList to set {end, end} to {item i of o's theKeys, item i of o's theValues}
end repeat

-- Create a record who is similar to records containing only user defined keys in AppleEvents
set theRecord to «class seld» of (record {«class usrf»:rawList} as record)

Last edited by KniazidisR (2021-01-24 07:06:52 am)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 14.1
Ram: 4 GB

Offline

 

#12 2021-01-24 10:55:27 am

bmose
Member
From:: Massachusetts
Registered: 2006-01-03
Posts: 381

Re: convert a list to a record

I'm not sure how to explain the discrepancy in speed testing results. Here are the results I get comparing the four fastest solutions with 1000 repetitions each:

Nigel's NSDictionary method:
       0.0002 seconds
My NSMutableDictionary method:
       0.0007 seconds
run script x with parameters {{«class usrf»:rawList}}:
       0.0009 seconds
«class seld» of (record {«class usrf»:rawList} as record):
       0.0009 seconds

Based on these speed test results, I would have to go with Nigel's NSDictionary method. (I've found over the years that when it comes to speed of execution, Nigel's solutions are virtually always the fastest! smile )

Still, I find the two Apple Event-based methods fascinating but mysterious. Can someone kindly explain the innards of how they work?

Last edited by bmose (2021-01-24 11:22:01 am)

Offline

 

#13 2021-01-24 11:12:09 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1456

Re: convert a list to a record

I decided to do some testing with an expanded list of 1000 items. Some suggestions didn't work in my test script but the results for the others are shown below. Given the size of the test list, I also modified Nigel's script to use a script object (see script below).

Nigel from post 9 (script-object enhanced) - 0.062 second

Nigel from post 9 - 0.421 second

KniazidisR from post 10 - 0.427 second

Bmose from post 6 - 0.645 second

Bmose first script from post 3 - 0.837 second

Bmose second script from post 3 - 5.832 seconds

Applescript:

use framework "Foundation"
use scripting additions

-- UNTIMED CODE --

set theList to {}
repeat 1000 times
   set the end of theList to {randomString(6), randomString(4)}
end repeat

on randomString(theStringLength)
   set randomChars to "ABCDEFGHIJKLMNOPQRSTUVWXYS"
   set theString to ""
   repeat theStringLength times
       set theString to theString & some item of randomChars
   end repeat
   return theString
end randomString

-- START TIME --

set startTime to current application's CFAbsoluteTimeGetCurrent()

-- TIMED CODE --

property || : current application

set theKeys to {}
set theValues to {}
repeat with currPair in my theList
   set {end of theKeys, end of theValues} to currPair's contents
end repeat
set theRecord to (||'s NSDictionary's dictionaryWithObjects:theValues forKeys:theKeys) as record

-- ELAPSED TIME

set elapsedTime to (current application's CFAbsoluteTimeGetCurrent()) - startTime
set nf to current application's NSNumberFormatter's new()
nf's setFormat:("0.000")
set elapsedTime to ((nf's stringFromNumber:elapsedTime) as text) & " seconds"

-- RESULT --

elapsedTime -- 0.062 seconds

-- theList # remove comment to view the result returned by theList
-- theRecord # remove comment to view the result returned by theRecord

Last edited by peavine (2021-01-29 07:31:00 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#14 2021-01-24 05:28:46 pm

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 1090

Re: convert a list to a record

Here's another run script method without the raw constant.

Applescript:

set theList to {{"Adam", "604"}, {"Eddie", "601"}, {"Susie", "602"}, {"Tim", "603"}, {"Steve", "603"}, {"Ben", "608"}, {"Dave", "607"}, {"Jimmy", 609}, {"Ive", "605"}, {"Will", "607"}}
set recordz to {}

repeat with anIndex from 1 to count theList
   set recordz's end to my (run script "{|" & (my (theList's item anIndex's item 1)) & "|: " & (quote & my (theList's item anIndex's item 2) & quote) & "}")
end repeat

recordz

Last edited by Marc Anthony (2021-01-24 05:30:06 pm)

Offline

 

#15 2021-01-29 04:04:12 am

wayland
Member
From:: Nha Trang
Registered: 2020-05-13
Posts: 76

Re: convert a list to a record

Thanks everybody, this was eye opening.

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)