Working with an array

How do you work with an array? I would like to get the number of times true is in the second item of each item in a list. Here is the code:

property imageSizes : {{64, true, 1, 1, 1}, {128, false, 1, 1, 1}, {256, false, 1, 1, 1}, {512, false, 1, 1, 1}, {1024, false, 1, 1, 1}}

count of (every item of imageSizes whose second item is true)

Unfortunately this does not work because filtered references do not work with script objects or lists (Danny Goodman’s book). Do you repeat through each of the items in the list counting them? Or is there a better way?

If this is the kind of list to analyze, seems that: a) you can coerce it to text; b) items 3, 4 and 5 of every member are the number 1. Whis is a useful coincidence.
You could use a workaround:

property imageSizes : {{64, true, 1, 1, 1}, {128, false, 1, 1, 1}, {256, false, 1, 1, 1}, {512, false, 1, 1, 1}, {1024, false, 1, 1, 1}}

set x to "" & imageSizes

set AppleScript's text item delimiters to "true111"
set trueCount to (rest of x's text items)'s length
set AppleScript's text item delimiters to {""}

trueCount --> 1

(or use simply “true” as delimiter)
Otherwise, use a repeat loop.

jj—

Is your method more efficient/speedier than this one? I’m still pretty green…


property imageSizes : {{64, true, 1, 1, 1}, {128, false, 1, 1, 1}, {256, false, 1, 1, 1}, {512, false, 1, 1, 1}, {1024, false, 1, 1, 1}}
set listNumber to count of lists of imageSizes
set itemNumber to 0
set sublistCount to 0

repeat with i from 1 to listNumber
	set itemNumber to second item of list i of imageSizes
	if itemNumber = true then
		set sublistCount to sublistCount + 1
	end if
end repeat

display dialog "The number of instances of the " & return & "second item in every sublist is " & sublistCount

Just curious…

Much more speedier!
My tests with a lengthy list and some more runs dropped 0.062 seconds against 10.955 (up to 100 times faster).
However, this will only work properly for this particular list.

For faster iteration in lists is recommended to copy the list to a script object’s property, typically through a prototype. Take a look to this comparison (requires Jon’s Commands for “the ticks” calculation, you can substitute it with “GetMilliSec” or whatever milli-timer):

property imageSizes : {{64, true, 1, 1, 1}, {128, false, 1, 1, 1}, {256, false, 1, 1, 1}, {512, false, 1, 1, 1}, {1024, false, 1, 1, 1}}

delay 3 --> if saved as app, wait while it is fully initialized

set start1 to the ticks --> checkpoint 1
repeat 100 times
	method1()
end repeat
set start2 to the ticks --> checkpoint 2
repeat 100 times
	method2(imageSizes)
end repeat
set finish to the ticks --> checkpoint 3

display dialog "Method 1: " & (start2 - start1) & " ticks" & return & "Method 2: " & (finish - start2) & " ticks"

to method1()
	set trueCount to 0
	repeat with i in imageSizes
		if i's item 2 then set trueCount to trueCount + 1
	end repeat
	trueCount --> 1
end method1

to method2(x)
	script empty
		property lst : x
		property cnt : 0
	end script
	repeat with i in empty's lst
		if i's item 2 then set empty's cnt to (empty's cnt) + 1
	end repeat
	empty's cnt
end method2

My results: 69 vs 4 (iMac G4) and 9 vs 3 (dual folk, 102 vs 21 for 1000 runs).

jj—

Wowee! You’re not kidding!

I’ve read various threads involving speed comparisons before, but never looked into performing them & don’t know much about measuring speed, using ticks, etc. Your example is really helpful.

Thank you.

If you are interested in speed, follow Nigel Garvey’s posts. He is one of the speeeeeeeediests! :lol:
http://bbs.applescript.net/search.php?search_author=Nigel+Garvey

Wow jj. Thanks, that’s the sort of answer I was looking for. I had tried method1, but I’m glad you showed be a faster way. I wonder why the script object method is faster though? They look very similar.

I’ve started learning about script objects, but have not begun using them. My ideas are about using them to hold data, just like a list. I understand it is possible to have the script object hold code to do things. How are they often used?

Scott

Hi, jj.

Thanks for the endorsement. (At least, I imagine your “speeeeeeeediests” comment was intended as an endorsement!) :wink:

You probably won’t mind, then, if I point out that the main advantage of using a script object to hold a list variable is that every time you access an item or items in the list, you can use a reference expression - in this case ‘empty’s lst’ - to refer to the list itself. Since this reference is compiled into the script, it works even faster than a reference generated on the fly and held in a variable. To demonstrate what I mean, compare this with your method2():

to method3(x)
  script empty
    property lst : x
  end script

  set cnt to 0
  repeat with i from 1 to (count x)
    if empty's lst's item i's item 2 then set cnt to cnt + 1
  end repeat

  cnt
end method3

:slight_smile:

I don’t understand why references are faster, against “direct targets” (eg, “item x of y’s z” against “tell z/y’s item x”)… Results are self-explaining, but I don’t really know why :?:

In my code, the variable “i” is a reference to an item within “empty’s lst”. So a ficticious apple-event log would be:
REPEAT WITH I IN EMPTY’S LST
→ i = empty’s lst’s item x (a reference to an item in a list)
IF I’S ITEM 2 THEN
→ i’s item 2 = true?

While your log would be:
→ i = x (integer)
→ empty’s lst’s item x’s item 2 = true?

If I delete the “if” statement, and keep only the repeat loop, my code is faster than yours (apparently): “repeat with i in empty’s lst” is faster than “repeat with i from 1 to (count x)”. So, assigning a value to the new variable “i” every iteration is not a problem.

I am again at the starting point: accessing items by reference is faster than targeting them directly, but I don’t know why. :cry:

(but I wanna use it for my lists needs) :wink:

Does the (Count of X) re-evaluate at each iteration? If so, that could explain the difference. It would re-count all of the items each time to determine if you’ve hit the end, while a reference would just keep going until it no longer referenced any items.

Nigel,
Accessing the list variable in a script object is much faster!
However, including the code in the script object did not speed things up. It is slightly slower, 8 ticks for method3, and 10 ticks for method4. (1000 iterations on an iBook, 800mHz. G3.)

script imageList
	property lst : imageSizes
	
	to countTrue()
		set cnt to 0
		repeat with i from 1 to (count lst)
			if lst's item i's item 2 then set cnt to cnt + 1
		end repeat
		cnt
	end countTrue
end script

to method4()
	tell imageList to countTrue()
end method4

I’m not really sure myself. :frowning: In the AppleScript Language Guide, the section dealing with the ‘a reference to’ operator explains that using a reference to a list can speed up access to the items in it, but it doesn’t explain why. Important concepts to grasp (I think) are:

  1. A reference is an expression of more than one word, used to describe something - eg. ‘empty’s lst’, ‘item 1 of lst’.
  2. The speed advantage we’re talking about comes when you include a reference to the list in the reference to a list item (‘item 1 of empty’s list’) rather than just including the list variable’s name (‘item 1 of lst’).
  3. This sub-reference is not actually to the list itself, but to the list variable.

You can’t get a reference to a local variable in a handler because local variables don’t have ‘parents’, but you can set up a script object with a property that points to the same list. You can then refer to the property in terms of its parent, the script object - as in “empty’s lst” or “lst of empty”.

Yes. Since the value of your ‘i’ is a reference, ‘i’s item 2’ also evaluates to ‘empty’s lst’s item x’s item 2’.

I haven’t tested that yet, but it’s an interesting result. It seems that my slight, overall advantage comes from having the reference compiled directly into the script rather than having to retrieve it from a variable first.

I don’t think (count x) does re-evalute each time, but I’ll check it out again later. I think the difference may simply be due to the fact that ‘count’ is a separate AppleScript instruction in my code, whereas it’s included in what jj’s loop format does anyway.

That’s a conveniently short way of saying it, but stricty speaking, I suppose it should be: accessing items in a list while referencing the list variable is faster than accessing the items using the list variable directly. Chris Nebel once said something about certain checks not being carried out when the list variable was referenced like this. In theory, it would be possible to make normal list access just as fast, but no-one at Apple had had time to think about whether it was safe to ditch the checks.

Ah, no. It’s not the fact that ‘lst’ is in a script object that counts. It’s the fact that the script object enables you to reference the list variable - that is, use an expression describing it in terms of that object. You should change your ‘if’ line to:

if imageList's lst's item i's item 2 then set cnt to cnt + 1

Alternatively, since your handler’s inside the script object too, you could use ‘my’:

if my lst's item i's item 2 then set cnt to cnt + 1

Wow. This is a long post! :wink:

Nigel wrote:

Changing method4()'s script object from:
if lst’s item i’s item 2 then set cnt to cnt + 1

to:
if my lst’s item i’s item 2 then set cnt to cnt + 1

does speed it up. It is now the fastest on my machine (only slightly faster than method3()). So there may be some small speed advantages in having code in a script object. But clearly as you were saying, accessing an item in a list while referencing the list’s variable is faster than accessing an item in a list while using the list’s variable directly. That my makes all the difference.

Scott