Extracting only specific records from a list of records?

Is there a way without iterating through all the records in a list to extract only the records that contain a certain property? For example, if I wanted to get all the records in a list that have the title:“two” property? In code, it would look like this:


set theList to {{title:"one"}, {title:"two"}, {title:"three"}}

set newList to <<all of the records in theList that contain title:"two">>
--{{title:"two"}}

To try to answer my own question, I’m thinking no, it’s not possible.

I think what I want to use is called a “filter reference” and from what I’ve read in the language guide, you cannot use filter references on lists or records. This is unfortunate because iterating through the list is not feasible.

So, what can I do now? Are there any other types of data structures in AppleScript like hash tables? Basically, I have a large (several thousands entries) list of titles of books and I need to be able to lookup related information about a book given it’s title. Currently, the book data is stored as records:

{title:“Angels & Demons”, author:“Dan Brown”, isbn:0671027360}
{title:“The Da Vinci Code”, author:“Dan Brown”, isbn:0385504209}

All the records are in a list. Now, if I’m given the title “The Da Vinci Code” I need to quickly look up the author, isbn, etc. Is this possible in AppleScript?

jamdr:

Two possibilities come to mind:

  1. Write a script to loop through all your records, writing three new lists, one each with authors, titles, and ISBNs. You would simply order the lists exactly the same, so that item 123 of each list was the same as item 123 of the record list. Searching one list would give you the info you need to extract the correct data from the other lists. This would also preserve your native list of records, in case you wanted to add to it in the future. After adding more records, just run the script again to generate a new set of lists.

  2. Use AppleWorks to create a database from your native record list. Although AW has some picky syntax issues, it is not difficult to script a new database and install your data into it. Once there, you can sort it, shape it, and report it however you want, and never lose a byte of data.

Good luck, and let me know if you would like more details on the AppleWorks angle.

casdvm

Apart from using an osax (which has its own conditions and caveats), iteration is the only way:

set theList to {{title:"one"}, {title:"two"}, {title:"three"}}
set newList to {}
repeat with itemRef in theList
	if itemRef contains {title:"two"} then set end of newList to itemRef's contents
end repeat
newList --> {{title:"two"}}

If you’re dealing with big lists then there are kludges you can use to speed this up (although it’ll never be especially fast because AppleScript is just plain dog-slow all round).

Those isbns look a bit suspect. It is an AppleScript list of AppleScript records you’re talking about, I assume? If so, iteration’s the only option. But you can maximise the iteration speed by using a reference to access the list (‘my l’ in the script below) and by making the search case sensitive (assuming all the entries are correctly capitalised).

script recordSearch
	property l : missing value
	property finds : missing value
	
	on seekTitle(recordList, theTitle)
		set my l to recordList
		set my finds to {}
		
		considering case
			repeat with i from 1 to (count recordList)
				if (title of item i of my l is theTitle) then set end of my finds to item i of my l
			end repeat
		end considering
		
		return my finds
	end seekTitle
end script

set theRecords to {{title:"Angels & Demons", author:"Dan Brown", isbn:6.7102736E+8}, {title:"The Da Vinci Code", author:"Dan Brown", isbn:385504209}}

tell recordSearch to seekTitle(theRecords, "The Da Vinci Code")
--> A list of all the records whose 'title' property has the value "The Da Vinci Code".

If that works for you, you can write similar handlers inside the script object to search on the author or isbn number.

Nineteen months later!: Corrected a goof whereby ‘finds’ wasn’t reinitialised each time. Thanks to Patrick Collins for his interest. :slight_smile:

You’d really be better off storing all this data in a proper database if you can. While ad-hoc vanilla AppleScript solutions are possible, they’re much more work to implement reliably and greatly inferior in terms of power and performance.

Thanks for the responses. AS is a lot more limited than I thought. If only its standard library were just a little bit bigger. I will look into some other options, maybe even another language. I’ve come to realize over the past few days of trying to learn AS that it basically has the same feature set as HyperTalk, which is 15+ years old. Too bad Apple doesn’t modernize it a bit.

p.s. those isbn’s were supposed to be quoted, too.

okay, I know this is probably a bit of stretch and not very elegant, but (in trying to stick to vanilla AS) could I do something like this:

  1. store all of the records in a text file, with one record on each line
  2. use “do shell script” and awk to retrieve only the line that contains “title:The Da Vinci Code”
  3. use “run script” on that line to convert it into an AS record that I can then extract the other info from

thoughts? :smiley:

Not that familiar with awk, but can’t you do ALL of queries/sorting in awk (to save time) then just report back exactly what you need?

-N

jamdr:

Take a closer look at Nigel’s script a few messages back. It really is quite elegant, short, and will acheive exactly what you are looking for. I am convinced that if you spend a little time studying it, you will understand how it works and can adapt it to fit your needs precisely. Even with several thousand records, a script with his search code will be plenty fast, especially if you are running a G5; although even a G4 should be sufficient with some extra RAM.

casdvm