trouble with repeat with i from 1 to count of

That helps even more! :slight_smile:

And given the proviso with your inversion, the asssignment-to-variable idea could be used if it was necessary to do things the original way round after all:

--tell application "Microsoft Excel"
--launch
--other script got these lists
set testList3combos15 to {{3, 9, 11}, {3, 12, 13}, {7, 8, 9}, {3, 6, 11}, {6, 7, 11}, {2, 3, 12}, {3, 6, 8}, {3, 5, 7}, {2, 11, 13}, {8, 9, 13}, {2, 9, 11}, {7, 10, 13}, {2, 6, 12}, {3, 6, 10}, {1, 2, 7}, {1, 3, 6}, {1, 9, 13}, {1, 2, 13}, {2, 4, 6}, {1, 6, 9}, {12, 13, 14}, {4, 7, 14}, {2, 12, 14}, {3, 4, 8}, {3, 10, 14}, {6, 8, 14}, {3, 12, 15}, {7, 8, 10}, {2, 4, 11}, {1, 13, 14}, {3, 4, 15}, {3, 4, 10}, {2, 12, 15}, {1, 7, 10}, {10, 13, 15}, {2, 4, 15}, {1, 4, 9}, {1, 13, 15}, {5, 9, 15}, {4, 8, 14}, {8, 11, 15}, {1, 12, 14}, {1, 8, 14}, {5, 8, 14}, {4, 10, 14}, {4, 10, 11}, {1, 14, 15}, {1, 8, 10}, {1, 10, 15}}

set checkList to {{6, 10, 4, 1, 11, 8}, {9, 3, 7, 4, 12, 13}, {14, 11, 4, 12, 10, 13}, {2, 7, 6, 9, 1, 5}, {7, 8, 2, 11, 15, 1}, {12, 3, 11, 1, 13, 15}, {15, 4, 10, 8, 5, 12}, {8, 13, 1, 12, 9, 3}, {7, 3, 6, 11, 8, 5}, {15, 2, 1, 13, 11, 9}}
set countchecklist to {}
repeat with i from 1 to (count checkList)
	set {a, b, c, d, e, f} to list i of checkList
	--return count of lists of checkList(returns 10 true)
	repeat with j from 1 to (count testList3combos15)
		set thisCombo to list j of testList3combos15
		set counttest to 0
		if thisCombo contains a then set counttest to counttest + 1
		if thisCombo contains b then set counttest to counttest + 1
		if thisCombo contains c then set counttest to counttest + 1
		if thisCombo contains d then set counttest to counttest + 1
		if thisCombo contains e then set counttest to counttest + 1
		if thisCombo contains f then set counttest to counttest + 1
		set end of countchecklist to counttest
		--return countchecklist--returns {1} true for list 1 of checkList
	end repeat
	-- return countchecklist --does,t get this far
end repeat
return countchecklist
--end tell

Yes, I think that makes a significant difference.

That looks a fair assumption.

Here’s another method, this time actually quite a bit slower. But it might scale a bit better with longer sublists.

use framework "Foundation"

set testList3combos15 to {{3, 9, 11}, {3, 12, 13}, {7, 8, 9}, {3, 6, 11}, {6, 7, 11}, {2, 3, 12}, {3, 6, 8}, {3, 5, 7}, {2, 11, 13}, {8, 9, 13}, {2, 9, 11}, {7, 10, 13}, {2, 6, 12}, {3, 6, 10}, {1, 2, 7}, {1, 3, 6}, {1, 9, 13}, {1, 2, 13}, {2, 4, 6}, {1, 6, 9}, {12, 13, 14}, {4, 7, 14}, {2, 12, 14}, {3, 4, 8}, {3, 10, 14}, {6, 8, 14}, {3, 12, 15}, {7, 8, 10}, {2, 4, 11}, {1, 13, 14}, {3, 4, 15}, {3, 4, 10}, {2, 12, 15}, {1, 7, 10}, {10, 13, 15}, {2, 4, 15}, {1, 4, 9}, {1, 13, 15}, {5, 9, 15}, {4, 8, 14}, {8, 11, 15}, {1, 12, 14}, {1, 8, 14}, {5, 8, 14}, {4, 10, 14}, {4, 10, 11}, {1, 14, 15}, {1, 8, 10}, {1, 10, 15}}

set checkList to {{6, 10, 4, 1, 11, 8}, {9, 3, 7, 4, 12, 13}, {14, 11, 4, 12, 10, 13}, {2, 7, 6, 9, 1, 5}, {7, 8, 2, 11, 15, 1}, {12, 3, 11, 1, 13, 15}, {15, 4, 10, 8, 5, 12}, {8, 13, 1, 12, 9, 3}, {7, 3, 6, 11, 8, 5}, {15, 2, 1, 13, 11, 9}}
set countchecklist to {}
repeat with list1 in checkList
	repeat with list2 in testList3combos15
		set newList to list1 & list2
		set end of countchecklist to (length of newList) - ((current application's NSSet's setWithArray:newList)'s |count|())
	end repeat
	return countchecklist --does,t get this far
end repeat
return countchecklist

Hello NIgel.

Yes, that works a lot better if the values aren’t unique. :slight_smile:

I was also thinking of making one, where the number of items in the tesLists, may vary, (since the number of items in it are named. That way, it isn’t necessary, to hardcode versions, for the number of items, Then the assertion about unique values in both lists must hold. This can of course also be inverted.


--launch
--other script got these lists
-- I surmise that all lists of checklist contains 3  unique numbers, and that testList3combos15 does the same.

set testList3combos15 to {{3, 9, 11}, {3, 12, 13}, {7, 8, 9}, {3, 6, 11}, {6, 7, 11}, {2, 3, 12}, {3, 6, 8}, {3, 5, 7}, {2, 11, 13}, {8, 9, 13}, {2, 9, 11}, {7, 10, 13}, {2, 6, 12}, {3, 6, 10}, {1, 2, 7}, {1, 3, 6}, {1, 9, 13}, {1, 2, 13}, {2, 4, 6}, {1, 6, 9}, {12, 13, 14}, {4, 7, 14}, {2, 12, 14}, {3, 4, 8}, {3, 10, 14}, {6, 8, 14}, {3, 12, 15}, {7, 8, 10}, {2, 4, 11}, {1, 13, 14}, {3, 4, 15}, {3, 4, 10}, {2, 12, 15}, {1, 7, 10}, {10, 13, 15}, {2, 4, 15}, {1, 4, 9}, {1, 13, 15}, {5, 9, 15}, {4, 8, 14}, {8, 11, 15}, {1, 12, 14}, {1, 8, 14}, {5, 8, 14}, {4, 10, 14}, {4, 10, 11}, {1, 14, 15}, {1, 8, 10}, {1, 10, 15}}

set checkList to {{6, 10, 4, 1, 11, 8}, {9, 3, 7, 4, 12, 13}, {14, 11, 4, 12, 10, 13}, {2, 7, 6, 9, 1, 5}, {7, 8, 2, 11, 15, 1}, {12, 3, 11, 1, 13, 15}, {15, 4, 10, 8, 5, 12}, {8, 13, 1, 12, 9, 3}, {7, 3, 6, 11, 8, 5}, {15, 2, 1, 13, 11, 9}}
set countchecklist to {}
set itemCount to count list 1 of testList3combos15

repeat with i from 1 to (count checkList)
	--return count of lists of checkList(returns 10 true)
	
	repeat with j from 1 to (count testList3combos15)
		set listToClassify to list j of testList3combos15
		set counttest to 0
		repeat with k from 1 to itemCount
			if item k of listToClassify is in (list i of checkList) then set counttest to counttest + 1
		end repeat
		set end of countchecklist to counttest
	end repeat
	# return countchecklist --does,t get this far
end repeat
return countchecklist

I’ve just noticed that the script and all our variations contain two ‘return countchecklist’ lines! The first, inside the repeat, is what’s been returning the results we’ve been seeing. It should be removed so that the line at the end returns the correct, much longer result.

Hello Nigel.

Good spot! :slight_smile:

I reran, your first example, without that return statement, towards my own, and I checked the results by text comparision in TextWrangler, it all worked out.

That was another way of doing it Shane. :slight_smile:

I’ve now commented out the offending line in my posts above in case bills doesn’t get this far in the technical discussion. I see McUsrII’s been doing the same thing. :slight_smile:

Yes.
And with a ‘#’ ! since ‘”’ entered directly into a post breaks the script, since it becomes translated into em-dash. :slight_smile:

We can of course optimize this a little bit further, should the OP need it, but it is smart to wait, until we know what he is after, because then it becomes at least a tad messier, with the script object.

I’ll just explain the math, for those who don’t understand who to compute the advantage of reducing the statements in a loop.

If you have one statement in a loop, that are iterated over 10 times, then the statement is executed 10 times, and this can be expressed as L1 X S. If you have 2 Loops, then the inner loop is exeuted the number of times you loop over it.
That can be expressed as L2 X L1 X S

So, in a case where the outer loop is executed 10 times, and the inner loop ten times and 5 statements are executed inside, then that is 10 X 10X 5 = 500, in this case, it is possible that we can get a way with 3 statements in the inner loop, reducing the total number of statements executed with 200. Therefore we look at possibilities for inverting some condition, to reduce the number of statements, if we can.

It is the same principle, as when one writes an SQL query, One should arrange the query, so that the largest number of items, are filtered away at the start, so the latter part of the query executes as fast as possible.

What’s happening on your computer? Two ordinary dashes (“–”) work perfectly well here.

In the current situation, the fewer inverted statements are checking longer lists. So in a worse-case scenario, each might take longer than one of the more numerous original statements it replaces. But overall, we may expect a speed gain. Still, as you’ve rightly born in mind, the inversion here is notionally checking the items in the ‘checkList’ lists rather than those in the ‘testList3combos15’ ones, so one must be careful to ensure that the two approaches do in fact correspond.

Hello.

I suspect the reason for the ‘”’ as em dash, to be that the internet is really standardized on iso-8859-1, and not UTF8.
So, I have an ‘outlandish’ keyboard. :slight_smile:

I agree, if the values in the CheckLists aren’t unique, then the approach is unusable.

And I also agree, to the fact that in the end, it is exactly the same number of comparisions that are performed inside the list, it is just that using contains or is in, reduces the number of statements, and that the containment operation, is faster than a single statement of itself. It also depends on if there are any match, or not in the list, and where in the list it is. I am still pretty sure that this is faster than having five statements, that checks three items, but if you had many lists with no matches, then I guess the other way around would be better-

Reading the comments about the speed efficiency in the approach to the filtering of lists prior to some loop reminded of something I remember reading some years ago: this stated that we could use Lists or Records. If I recall correctly ( I think it was the Kochan book on AS…) the suggestion was that it was much more efficient in terms of speed to access a large set of records compared to looping through lists.

I understand that perhaps it can be more complicated to think about the correct structure of records, and lists are easy to set up and deal with, but as the data set gets larger, the payoff increases.

This is an abstract statement coming from a diminishing memory and I offer no code as an example, but I would be interested to hear if anybody has a formed view on this.

Hi.

I don’t recall anything of that nature. By and large, I think that dealing with lists is faster than dealing with records ” in AppleScript, anyway. And of course if you’re starting with lists, as here, there’d be the additional time needed to transfer their data to records. I can’t really say any more than that as I can’t fully picture what you’re describing.

There is one phenomenon that’s often exploited. Access to items in long lists is usually very much faster if the references to the items include references to the list variables, in the context of the script in which they occur. eg:

-- someList is a variable to which is assigned a long list.

 -- Normal item reference.
item x of someList

-- Item reference where the list variable is referenced too:
item x of someList of someScript

But I don’t think that’s what you had in mind.

Edit: omitted word noticed and rectified.

Hi
Thanks for the help.
I had (set countchecklist to {}) in the wrong place to get the results I wanted.
Basically what I was doing was checking which of the 6 number list got the most 3 number matches of the 3 number lists.
Will have to remember not to use the same variable twice.
The numbers are unique.
Heres how it turned out. Both versions give the same result.

--tell application "Microsoft Excel"
--launch
--other script got these lists
set testList3combos15 to {{3, 9, 11}, {3, 12, 13}, {7, 8, 9}, {3, 6, 11}, {6, 7, 11}, {2, 3, 12}, {3, 6, 8}, {3, 5, 7}, {2, 11, 13}, {8, 9, 13}, {2, 9, 11}, {7, 10, 13}, {2, 6, 12}, {3, 6, 10}, {1, 2, 7}, {1, 3, 6}, {1, 9, 13}, {1, 2, 13}, {2, 4, 6}, {1, 6, 9}, {12, 13, 14}, {4, 7, 14}, {2, 12, 14}, {3, 4, 8}, {3, 10, 14}, {6, 8, 14}, {3, 12, 15}, {7, 8, 10}, {2, 4, 11}, {1, 13, 14}, {3, 4, 15}, {3, 4, 10}, {2, 12, 15}, {1, 7, 10}, {10, 13, 15}, {2, 4, 15}, {1, 4, 9}, {1, 13, 15}, {5, 9, 15}, {4, 8, 14}, {8, 11, 15}, {1, 12, 14}, {1, 8, 14}, {5, 8, 14}, {4, 10, 14}, {4, 10, 11}, {1, 14, 15}, {1, 8, 10}, {1, 10, 15}}

set checkList to {{6, 10, 4, 1, 11, 8}, {9, 3, 7, 4, 12, 13}, {14, 11, 4, 12, 10, 13}, {2, 7, 6, 9, 1, 5}, {7, 8, 2, 11, 15, 1}, {12, 3, 11, 1, 13, 15}, {15, 4, 10, 8, 5, 12}, {8, 13, 1, 12, 9, 3}, {7, 3, 6, 11, 8, 5}, {15, 2, 1, 13, 11, 9}}

set HighCountList to {}
repeat with i from 1 to (count checkList)
	set countchecklist to {}
	repeat with j from 1 to (count testList3combos15)
		set counttest to 0
		if list j of testList3combos15 contains (item 1 of list i of checkList) then set counttest to counttest + 1
		if list j of testList3combos15 contains (item 2 of list i of checkList) then set counttest to counttest + 1
		if list j of testList3combos15 contains (item 3 of list i of checkList) then set counttest to counttest + 1
		if list j of testList3combos15 contains (item 4 of list i of checkList) then set counttest to counttest + 1
		if list j of testList3combos15 contains (item 5 of list i of checkList) then set counttest to counttest + 1
		if list j of testList3combos15 contains (item 6 of list i of checkList) then set counttest to counttest + 1
		set end of countchecklist to counttest
	end repeat
	--gets 3 matches	
	set CountHighHits to 0
	repeat with k from 1 to the count of the countchecklist
		if item k of countchecklist is 3 then set CountHighHits to CountHighHits + 1
	end repeat
	set end of HighCountList to CountHighHits
end repeat
--get highest number of 3 hits
set the highHit to ""
repeat with i from 1 to the count of the HighCountList
	set thisItem to item i of the HighCountList
	if the highHit is "" then
		set the highHit to thisItem
	else if thisItem is greater than the highHit then
		set the highHit to item i of the HighCountList
	end if
end repeat
--finds 1st highest match in list
set the listCount to 0
repeat with i from 1 to the count of the HighCountList
	set thisItem to item i of the HighCountList
	if thisItem is less than highHit then set listCount to listCount + 1
	if thisItem is highHit then exit repeat
end repeat
set MostMatches to list (listCount + 1) of checkList

return MostMatches

--end tell
--launch
--other script got these lists
-- I surmise that all lists of checklist contains 3  unique numbers, and that testList3combos15 does the same.

set testList3combos15 to {{3, 9, 11}, {3, 12, 13}, {7, 8, 9}, {3, 6, 11}, {6, 7, 11}, {2, 3, 12}, {3, 6, 8}, {3, 5, 7}, {2, 11, 13}, {8, 9, 13}, {2, 9, 11}, {7, 10, 13}, {2, 6, 12}, {3, 6, 10}, {1, 2, 7}, {1, 3, 6}, {1, 9, 13}, {1, 2, 13}, {2, 4, 6}, {1, 6, 9}, {12, 13, 14}, {4, 7, 14}, {2, 12, 14}, {3, 4, 8}, {3, 10, 14}, {6, 8, 14}, {3, 12, 15}, {7, 8, 10}, {2, 4, 11}, {1, 13, 14}, {3, 4, 15}, {3, 4, 10}, {2, 12, 15}, {1, 7, 10}, {10, 13, 15}, {2, 4, 15}, {1, 4, 9}, {1, 13, 15}, {5, 9, 15}, {4, 8, 14}, {8, 11, 15}, {1, 12, 14}, {1, 8, 14}, {5, 8, 14}, {4, 10, 14}, {4, 10, 11}, {1, 14, 15}, {1, 8, 10}, {1, 10, 15}}

set checkList to {{6, 10, 4, 1, 11, 8}, {9, 3, 7, 4, 12, 13}, {14, 11, 4, 12, 10, 13}, {2, 7, 6, 9, 1, 5}, {7, 8, 2, 11, 15, 1}, {12, 3, 11, 1, 13, 15}, {15, 4, 10, 8, 5, 12}, {8, 13, 1, 12, 9, 3}, {7, 3, 6, 11, 8, 5}, {15, 2, 1, 13, 11, 9}}
set HighCountList to {}
repeat with i from 1 to (count checkList)
	set thisCheck to list i of checkList
	set countchecklist to {}
	
	repeat with j from 1 to (count testList3combos15)
		set {a, b, c} to list j of testList3combos15
		
		
		set counttest to 0
		if a is in thisCheck then set counttest to counttest + 1
		if b is in thisCheck then set counttest to counttest + 1
		if c is in thisCheck then set counttest to counttest + 1
		set end of countchecklist to counttest
	end repeat
	--gets 3 matches	
	set CountHighHits to 0
	repeat with k from 1 to the count of the countchecklist
		if item k of countchecklist is 3 then set CountHighHits to CountHighHits + 1
	end repeat
	set end of HighCountList to CountHighHits
	
end repeat

--gets the highest amount of 3 matches
set the highHit to ""
repeat with i from 1 to the count of the HighCountList
	set thisItem to item i of the HighCountList
	if the highHit is "" then
		set the highHit to thisItem
	else if thisItem is greater than the highHit then
		set the highHit to item i of the HighCountList
	end if
end repeat
--finds 1st highest match in list
set the listCount to 0
repeat with i from 1 to the count of the HighCountList
	set thisItem to item i of the HighCountList
	if thisItem is less than highHit then set listCount to listCount + 1
	if thisItem is highHit then exit repeat
end repeat

set MostMatches to list (listCount + 1) of checkList
return MostMatches

Thanks again
bills

Hi bills.

Thanks for getting back with your final script.

If you’re interested, besides the other optimisations we’ve mentioned above, this part at the end of the script(s) .

set the highHit to ""
repeat with i from 1 to the count of the HighCountList
	set thisItem to item i of the HighCountList
	if the highHit is "" then
		set the highHit to thisItem
	else if thisItem is greater than the highHit then
		set the highHit to item i of the HighCountList
	end if
end repeat
--finds 1st highest match in list
set the listCount to 0
repeat with i from 1 to the count of the HighCountList
	set thisItem to item i of the HighCountList
	if thisItem is less than highHit then set listCount to listCount + 1
	if thisItem is highHit then exit repeat
end repeat
set MostMatches to list (listCount + 1) of checkList

. can be condensed to .

set the highHit to ""
repeat with i from 1 to (count the HighCountList)
	set thisItem to item i of the HighCountList
	if the highHit is "" or thisItem is greater than the highHit then
		set the highHit to thisItem
		set highHitIndex to i
	end if
end repeat
set MostMatches to list highHitIndex of checkList

Thanks for your thought Nigel, I do realize that if we start with a list,then that is what we have to address.But you are right, I had something else in mind. I will have a rummage and see if I can find the reference. It was an obscure point I seem to recall, and I do recall trying it out on using Database Events. I will circle back later.

Further to my note regarding the speed of list recursions and my recollection of the more efficient, in some cases, uses of records, I was correct in my hunch that it was related to the use of Database events (built in to every Mac). See Soghoian & Cheeseman, page 700 on The use of records and DB events. The speed gain, they assert occurs through the ability to use the ‘get all … Whose…’ clause because “it is the target application Database Events that is evaluating these statements, and it is very fast.”
But this is almost certainly a subject for discussion in a separate post.

But in any case, here is a great link with full working example.
https://iworkautomation.com/numbers/sqlite.html

Hi
Thanks,will use your compression Nigel
bills

Hi Tim.

As I suspected when I saw your previous post mentioning Database Events and ‘whose’ filters, the kind of ‘record’ you’re thinking of is a class of object belonging to the Database Events application, not the ‘record’ belonging to the core AppleScript language. Both are “AppleScript” in the broader sense; but one is a term defined in Database Events’s scripting dictionary (corresponding to a record in a database) and the other, as I said, is part of the core language. If you mention ‘record’ within a ‘tell application “Database Events”’ statement, it’s understood to be the Database Events term. Otherwise it’s the “vanilla” (core AppleScript) term.

‘whose’ filters aren’t implemented in the core language, but may be implemented by scriptable applications. They can make life easier for scripters, but often turn out to be quite slow in operation. Some applications are worse than others. I suspect it’s something to do with the way their AppleScript abilities are bolted on after they’ve been designed to be operated manually. I’ve never used Database Events myself, but it was specifically designed to be scripted, so maybe its ‘whose’ filters are indeed as fast as claimed in the Soghoian/Cheeseman book.

Hello Tim.

Thanks for a great link, I will certainly read about those workflows.

Just to clarify, when wrote that sentence, I had an SQL query, from an RDBMS (Relational Database Management System) in mind, this can of course also be utilized with dabase events, so that you specify a query that will return the lowest number of records, (if that is the most feasible) that way, you let database events do most of the work.

Edit

mouramartins did an analysis, that is interesting concerning File Maker Pro: MacScripter / Getting values from FileMaker using whose clauses.