Notifications
Clear all

[Closed] Lambda Expressions in Maxscript – II

I think that finaly I’ve found a balanced solution between performance and usability.
It would be nice if you, experienced scripters, try it and give your feedback. Perhaps we arrive to something which is really worth using in our scripts.

Here’s the code. It’s just a global variable holding the struct for comparers and the ArrayQueryStruct to apply it to any array we want to inspect.


	global MXSComparer =
	(
		struct MXSComparer
		(
			lambdaFN,
			
			Point3Comparer =
			(
				struct point3Comparer
				(
					_zero = 0,
					refPos = [0,0,0],
					fn _Value x = distance x refPos ,
					fn Equals x y = (x == y),	--	Equality of Point3. NOT VALUE EQUALITY
					fn SortASC x y =
					(
						d1 = distance x refPos
						d2 = distance y refPos
						case of
						(
							(d1 < d2):-1
							(d1 > d2):1
							default:0
						)
					),
					fn SortDES x y =
					(
						d1 = distance x refPos
						d2 = distance y refPos
						case of
						(
							(d1 < d2):1
							(d1 > d2):-1
							default:0
						)
					),
					on create do
					(
					)		
				)
				point3Comparer()
			),
			
			IndexComparer =
			(
				struct IndexComparer	-- Comparison based on equality of n'th element in subarray
				(
					_zero = 0,
					Index = 1,
					fn _Value x = x[Index],
					fn Equals x y = -- all items in sub-array elements are equal to the ones of the given array of the same size. NOT VALUE EQUALITY
									(
										isEqual = true
										for i = 1 to x.count while isEqual do isEqual = (x[i] == y[i])
										isEqual
									),
					fn SortASC x y =
					(
						d1 = x[Index]
						d2 = y[Index]
						case of
						(
							(d1 < d2):-1
							(d1 > d2):1
							default:0
						)
					),
					fn SortDES x y =
					(
						d1 = x[Index]
						d2 = y[Index]
						case of
						(
							(d1 < d2):1
							(d1 > d2):-1
							default:0
						)
					),
					on create do
					(
					)		
				)
				IndexComparer()
			),
			
			SumArrayComparer =
			(
				struct SumArrayComparer
				(
					_zero = 0,
					fn _Value x = (sum = 0; for i in x do sum += i; sum),		-- Sum of elements in subArray
					fn Equals x y = -- all items in sub-array elements are equal to the ones of the given array of the same size. NOT VALUE EQUALITY
									(
										isEqual = true
										for i = 1 to x.count while isEqual do isEqual = (x[i] == y[i])
										isEqual
									),
					fn SortASC x y =
					(
						d1 = (sum = 0; for i in x do sum += i; sum)
						d2 = (sum = 0; for i in y do sum += i; sum)
						case of
						(
							(d1 < d2):-1
							(d1 > d2):1
							default:0
						)
					),
					fn SortDES x y =
					(
						d1 = (sum = 0; for i in x do sum += i; sum)
						d2 = (sum = 0; for i in y do sum += i; sum)
						case of
						(
							(d1 < d2):1
							(d1 > d2):-1
							default:0
						)
					),
					on create do
					(
					)		
				)
				SumArrayComparer()	
			),
			
			CaseInsensitive =
			(
				struct CaseInsensitive
				(
					_zero = "",
					fn _Value x = toLower x,
					fn Equals x y = ((stricmp x y) == 0),
					fn SortASC x y =
					(
						d1 = toLower x
						d2 = toLower y
						case of
						(
							(d1 < d2):-1
							(d1 > d2):1
							default:0
						)
					),
					fn SortDES x y =
					(
						d1 = toLower x
						d2 = toLower y
						case of
						(
							(d1 < d2):1
							(d1 > d2):-1
							default:0
						)
					),
					on create do
					(
					)		
				)
				CaseInsensitive()	
			),
			
			NodeDistanceComparer =
			(
				struct NodeDistanceComparer
				(
					_zero = 0,
					refPos = [0,0,0],
					fn _Value x = distance x.pos refPos,
					fn Equals x y = (x == y),	--	Equality of Nodes. NOT VALUE EQUALITY
					fn SortASC x y =
					(
						d1 = distance x.pos refPos
						d2 = distance y.pos refPos
						case of
						(
							(d1 < d2):-1
							(d1 > d2):1
							default:0
						)
					),
					fn SortDES x y =
					(
						d1 = distance x.pos refPos
						d2 = distance y.pos refPos
						case of
						(
							(d1 < d2):1
							(d1 > d2):-1
							default:0
						)
					),
					on create do
					(
					)		
				)
				NodeDistanceComparer()	
			),
			
			NodeSizeComparer =
			(
				struct NodeSizeComparer
				(
					_zero = 0,
					fn _Value x = (bb = nodeGetBoundingBox x x.transform; D = distance bb[1] bb[2]; Vol = D*D*D/3./(sqrt 3); side = Vol^(1/3.)),
					fn Equals x y = (x == y),	--	Equality of Nodes. NOT VALUE EQUALITY
					fn SortASC x y =
					(
						d1 = (bb = nodeGetBoundingBox x x.transform; D = distance bb[1] bb[2]; Vol = D*D*D/3./(sqrt 3); side = Vol^(1/3.))
						d2 = (bb = nodeGetBoundingBox y y.transform; D = distance bb[1] bb[2]; Vol = D*D*D/3./(sqrt 3); side = Vol^(1/3.))
						case of
						(
							(d1 < d2):-1
							(d1 > d2):1
							default:0
						)
					),
					fn SortDES x y =
					(
						d1 = (bb = nodeGetBoundingBox x x.transform; D = distance bb[1] bb[2]; Vol = D*D*D/3./(sqrt 3); side = Vol^(1/3.))
						d2 = (bb = nodeGetBoundingBox y y.transform; D = distance bb[1] bb[2]; Vol = D*D*D/3./(sqrt 3); side = Vol^(1/3.))
						case of
						(
							(d1 < d2):1
							(d1 > d2):-1
							default:0
						)
					),
					on create do
					(
					)		
				)
				NodeSizeComparer()	
			),
				
			on create do
			(
			)		
		)
		MXSComparer()
	)


	struct ArrayQuery
	(
		mainArray,
		ResultArray,
		
		useComp = false,
		comparerParam = "",
		Comparer, 
		fn useComparer use = 
		(
			useComp = use
			comparerParam = if useComp then " Comparer:Comparer" else ""
		),
		
		fn setComparer comparerName =
		(
			comparerName = toLower comparerName
			Comparer = case comparerName of
			(
				"point3comparer":  			::MXSComparer.Point3Comparer
				"indexcomparer":   			::MXSComparer.IndexComparer
				"sumarraycomparer":  		::MXSComparer.SumArrayComparer
				"caseinsensitive":  			::MXSComparer.CaseInsensitive
				"nodedistancecomparer":  	::MXSComparer.NodeDistanceComparer
				default: (print "Unknown Comparer"; undefined)
			)
		),
		
		-- Query Functions
		fn _where LA =
		(
			LA = LA as string
			assignPos = findString  LA "=>"
			fnExpression = (substring LA 1 (assignPos - 1)) + comparerParam + " = " + (substring LA (assignPos+2) -1)
			LA = execute ("::MXSComparer.lambdaFN = fn GlobalLambdaFN " + fnExpression)
			
			if useComp then
			(
				ResultArray = for item in ResultArray where (LA item Comparer:Comparer) collect item
			)
			else
			(
				ResultArray = for item in ResultArray where (LA item) collect item
			)
			return (this) 
		),
		fn Change LA =
		(
			LA = LA as string
			assignPos = findString  LA "=>"
			fnExpression = (substring LA 1 (assignPos - 1)) + " = " + (substring LA (assignPos+2) -1)
			LA = execute ("::MXSComparer.lambdaFN = fn GlobalLambdaFN " + fnExpression)
			
			ResultArray = for item in ResultArray collect (LA item)
			return (this) 
		),
		fn GroupBy LA =
		(
			LA = LA as string
			assignPos = findString  LA "=>"
			fnExpression = (substring LA 1 (assignPos - 1)) + comparerParam + " = " + (substring LA (assignPos+2) -1)
			LA = execute ("::MXSComparer.lambdaFN = fn GlobalLambdaFN " + fnExpression)
			
			if useComp then
			(
				tempResult = #()
				notFound = #{1..ResultArray.count}
				count = 0
				for i = 1 to ResultArray.count where notFound[i] do
				(
					count += 1
					append tempResult #()
					append tempResult[count] ResultArray[i]
					check = LA ResultArray[i] Comparer:Comparer
					
					for j = i+1 to ResultArray.count where (notFound[j] and ((LA ResultArray[j] Comparer:Comparer) == check)) do
					(
						notFound[j] = false
						append tempResult[count] ResultArray[j]
					)
				)
				ResultArray = deepcopy tempResult
			)
			else
			(
				tempResult = #()
				notFound = #{1..ResultArray.count}
				count = 0
				for i = 1 to ResultArray.count where notFound[i] do
				(
					count += 1
					append tempResult #()
					append tempResult[count] ResultArray[i]
					check = LA ResultArray[i]
					
					for j = i+1 to ResultArray.count where (notFound[j] and ((LA ResultArray[j]) == check)) do
					(
						notFound[j] = false
						append tempResult[count] ResultArray[j]
					)
				)
				ResultArray = deepcopy tempResult
			)
			return (this) 
		),
		fn maxObjectQuery obj LA =
		(
			LA = LA as string
			assignPos = findString  LA "=>"
			fnExpression = (substring LA 1 (assignPos - 1)) + " = " + (substring LA (assignPos+2) -1)
			LA = execute ("::MXSComparer.lambdaFN = fn GlobalLambdaFN obj " + fnExpression)
				
			ResultArray = for item in ResultArray where (LA obj item) collect (item)
			return (this) 
		),
		-- Filter Functions
		fn MakeUnique =
		(
			if useComp then
			(
				tempResult = #()
				found = #{1..ResultArray.count}
				for i = 1 to ResultArray.count where found[i] do
				(
					append tempResult ResultArray[i]
					for j = i+1 to ResultArray.count where found[j] do
					(
						if Comparer.Equals ResultArray[i] ResultArray[j] do found[j] = false
					)
				)
				ResultArray = deepcopy tempResult
			)
			else
			(
				ResultArray = makeUniqueArray ResultArray
			)
			return (this) 
		),
		fn Intersect otherArray =
		(
			if useComp then
			(
				tempResult = #()
				for item in ResultArray do
				(
					notfound = true
					for item2 in otherArray while notfound do
					(
						if (Comparer.Equals item item2) do (notfound = false; append tempResult item)
					)
				)
				ResultArray = deepcopy tempResult
			)
			else
			(
				ResultArray = for item in ResultArray where (findItem otherArray item != 0) collect item
			)
			return (this) 
		),
		fn Except otherArray =
		(
			if useComp then
			(
				tempResult = #()
				for item in ResultArray do
				(
					notfound = true
					for item2 in otherArray while notfound do
					(
						if (Comparer.Equals item item2) do (notfound = false)
					)
					if notfound do append tempResult item
				)
				ResultArray = deepcopy tempResult
			)
			else
			(
				ResultArray = for item in ResultArray where (findItem otherArray item == 0) collect item 
			)
			return (this) 
		),
		fn Union otherArray =
		(
			if useComp then
			(
				ResultArray = (ResultArray + otherArray)
				MakeUnique()
			)
			else
			(
				ResultArray = makeUniqueArray (ResultArray + otherArray)
			)
			return (this) 
		),
		-- Final Functions
		fn Select =
		(
			Result = deepCopy ResultArray 
			ResultArray = deepCopy mainArray
			return Result
		),
		fn Count = 
		(
			Result = ResultArray.count
			ResultArray = deepCopy mainArray
			return Result
		),
		fn Sum =
		(
			if useComp then
			(
				suma = Comparer._zero
				for item in ResultArray do (suma += Comparer._Value item)
			)
			else
			(
				arrayClass = classof ResultArray[1]
				suma = if arrayClass == string then "" else 0
				for item in ResultArray do (suma += item)
			)
			ResultArray = deepCopy mainArray
			return suma
		),
		fn Average =
		(
			numItems = ResultArray.count
			result = (sum() as float)/numItems
			return result
		),
		fn SortASC =	
		(
			if useComp then
			(
				qsort ResultArray Comparer.sortASC
				Result = deepCopy ResultArray
			)
			else
			(
				sort ResultArray
				Result = deepCopy ResultArray
			)
			ResultArray = deepCopy mainArray
			return Result
		),
		fn SortDES =	
		(
			if useComp then
			(
				qsort ResultArray Comparer.sortDES
				Result = deepCopy ResultArray
			)
			else
			(
				fn SortDescending x y =
				(
					case of
					(
						(x < y):1
						(x > y):-1
						default:0
					)
				)
				qsort ResultArray SortDescending
				Result = deepCopy ResultArray
			)
			ResultArray = deepCopy mainArray
			return Result
		),
		fn SortByIndex Index:1 Dir:"ASC"=	-- Sort multiArray by index. Dir: "ASC" ascending; "DES" descending
		(
			Dir = toLower Dir
			direction = if Dir == "des" then -1 else 1
			BaseIndex = Index
			
			fn Sorting x y BaseIndex:BaseIndex direction:direction =
			(
				case of
				(
					(x[BaseIndex] < y[BaseIndex]): (-1 * direction)
					(x[BaseIndex] > y[BaseIndex]): (direction)
					default:0
				)
			)
			qsort ResultArray Sorting BaseIndex:BaseIndex direction:direction
			Result = deepCopy ResultArray
			ResultArray = deepCopy mainArray
			return Result
		),
		fn FindAllIndex LA = -- 'index' == reserved word for array index
		(
			LA = LA as string
			assignPos = findString  LA "=>"
			fnExpression = (substring LA 1 (assignPos - 1)) + comparerParam + " = " + (substring LA (assignPos+2) -1)
			LA = execute ("::MXSComparer.lambdaFN = fn GlobalLambdaFN index " + fnExpression)
				
			if useComp then
			(
				ResultIndex = for id = 1 to ResultArray.count where (LA id ResultArray[id] Comparer:Comparer) collect id
			)
			else
			(
				ResultIndex = for id = 1 to ResultArray.count where (LA id ResultArray[id]) collect id
			)
			
			ResultArray = deepCopy mainArray
			return ResultIndex
		),
		fn FindIndex LA = -- 'index' == reserved word for array index
		(
			LA = LA as string
			assignPos = findString  LA "=>"
			fnExpression = (substring LA 1 (assignPos - 1)) + comparerParam + " = " + (substring LA (assignPos+2) -1)
			LA = execute ("::MXSComparer.lambdaFN = fn GlobalLambdaFN index " + fnExpression)
			
			ResultIndex = -1	
			if useComp then
			(
				for id = 1 to ResultArray.count where (LA id ResultArray[id] Comparer:Comparer) while (ResultIndex == -1) do (ResultIndex = id)
			)
			else
			(
				for id = 1 to ResultArray.count where (LA id ResultArray[id]) while (ResultIndex == -1) do (ResultIndex = id)
			)
			
			ResultArray = deepCopy mainArray
			return ResultIndex
		),
		on create do
		(
			ResultArray = deepCopy mainArray
		)
	)

13 Replies

Reserved for using explanation

User’s guide:
The ‘ArrayQuery’ struct purpose is to query arrays and multiarrays using predefined functions through a kind of ‘lambda expressions’.
The general syntax is:
<queryStruct> = ArrayQuery <array>
=====> Assigns the array to query to an ArrayQuery struct

The predefined query functions are divided in three groups:

  • Query Functions: functions that query the array through a lambda expression (_Where, Change, GroupBy, maxObjectQuery). The result of this query is a value held in the QueryStruct, so you should apply a ‘Final Function’ to use the result.
  • Filter Functions: these functions have the same behaviour than ‘Query Functions’, but they don’t use lambda expressions (MakeUnique, Intersect, Except, Union).
  • Final Functions: these functions give a result of your query that you can store in any variable (Select, Count, Sum, Average, SortASC, SortDES, SortByIndex, FindAllIndex, FindIndex). Some of these functions use a lambda expression to work (FindAllIndex, FindIndex).

The general syntax is:
<Value> = <queryStruct>.[B]FinalFunction/B
=====> Apply a final function to the array
<Value> = (<queryStruct>.QueryFunction(#‘lambda expression’)).[B]FinalFunction/B
=====> Apply a query function to the array and then get a result through a final function
<Value> = (<queryStruct>.[B]FilterFunction/B).[B]FinalFunction/B
=====> Apply a filter function to the array and then get a result through a final function

You can apply as many query and filter functions as needed to a query result, always adding parenthesis to the prior query:
<Value> = ((<queryStruct>.QueryFunction(#‘lambda expression’)).[B]FilterFunction/B).[B]FinalFunction/B
<Value> = (((<queryStruct>.QueryFunction(#‘lambda expression’)).[B]FilterFunction/B).QueryFunction(#‘lambda expression’)).[B]FinalFunction/B

Lambda Expressions are a name (#’<name>) or a string (“string”) with next syntax:
<var> => <var expression>
where <var> is a variable name designating the array item and <var expression> is a maxscript expression using the <var> variable.
FindAllIndex and FindIndex final functions can use the reserved word ‘index’ in the <var expression> that points to the index of the <var> element in the array.

You can use a predefined Comparer in your query (CaseInsensitive, Point3Comparer, NodeDistanceComparer, SumArrayComparer, IndexComparer). In this case, all query functions will work with defined values and equalities in the selected Comparer.
To do it, the syntax is:
<queryStruct>.[B]useComparer/B
<queryStruct>.setComparer “ComparerName”

You can use Comparer definitions in lambda expresions using the Comparer struct, for example:
#‘x => Comparer._Value x > 10’ to query for values greater than 10 using ‘Comparer Value’
#‘x => Comparer.Equals x 10’ to query for values equal to 10 using ‘Comparer Value’
And set the Comparer parameters via:
<queryStruct>.Comparer.parameterName = <newValue>
All these parameters are defined at the top of each Comparer Struct Definition.

Reserved for general arrays query examples

QUERY FUNCTIONS

  • _Where(#‘lambda expression’): general purpose query function. Lambda expression must evaluate to <boolean>.
    Ex.: (QArray._Where(#’node => node.radius > 15.0)).Select()

  • Change(#‘lambda expression’): function to make changes to the query array. It doesn’t admit Comparer use. Lambda expression can evaluate to any <value>
    Ex.1: (QArray.Change(#’x => x^2)).Select() ____ (returns all elements in the array powered by 2)
    Ex.2: (QArray.Change(#’subArrayItem => subArrayItem[2])).Select() ____ (returns a new array with only 2nd element of each subArrayItem in the query array)

  • GroupBy(#‘lambda expression’): function to make groups based on the Lambda expression, that can evaluate to any <value>, included boolean. Each group is stored as a subArray of the result Array.
    Ex.1: (QArray.GroupBy(#’item => item[3]>7)).Select() ____ (returns two subgroups)
    Ex.2: (QArray.GroupBy(#’item => item[3])).Select() ____ (returns as many subgroups as different values exist of 3rd element in subArrays of the query array)
    Ex.3: (QArray.GroupBy(#’item => item.radius)).Select() ____ (returns subgroups of elements with the same radius)

  • maxObjectQuery <maxObject> (#‘lambda expression’): function to query the array using a maxObject in the Lambda expression, that must evaluate to <boolean>. There’s a reserved word ‘obj’ for the maxObject in the Lambda expression. This function doesn’t allow Comparer use.
    Ex.: (QArray.maxObjectQuery sp (#‘vert => (getvert obj vert).z < 0’)).select() ____ (returns all items for whose the evaluation of lambda expression is true (where ‘sp’ is the maxObject passed to the lambda function)

Example 1: ‘GroupBy’
Group a cloud of Point3 by their Y coordinate

(
	myArray = for i = 1 to 1000 collect [random 0 100, random 0 100, random 0 100]
	
	QArray = ArrayQuery myArray
	QArray.useComparer(false)
	
	t1 = timestamp()
	groupedArray = (QArray.GroupBy(#'coord => coord.Y')).select()
	t2 = timestamp()
	format "Result = %
" groupedArray
	format "Result.count= %
" groupedArray.count	--	101 groups
	format "time1= %ms
" (t2-t1)				--	120ms for 1000 items
)

Reserved for arrays query using Comparer examples

Example 1: ‘NodeDistanceComparer’
We want to select all nodes that have their coord X positive and are at a distance less than 50 units from a target node:

(
	delete objects
	for i = 1 to 2000 do point prefix:"aaa" pos:[random -100 100, random -100 100, random -100 100]
	nodeArray = objects as array
	refNode = sphere name:"refNode" radius:50 pos:[random -100 100, random -100 100, random -100 100]

	t1 = timestamp()
	Qnodes = ArrayQuery nodeArray
	Qnodes.useComparer(true)
	Qnodes.setComparer "NodeDistanceComparer" 
	Qnodes.Comparer.refPos = refNode.pos
	
	theNodes =((Qnodes._Where(#'node => node.pos.x >= 0'))._Where(#'dist => Comparer._value dist < 50')).select()
	t2 = timestamp()
	select theNodes
	
	format "NODE DISTANCE COMPARER
"
	format "theNodes = %
" theNodes
	format "theNodes.count= %
" theNodes.count
	format "time= %ms
" (t2 - t1)	--	9ms for 2000 nodes
)

Example 2: ‘SumArrayComparer’

(
	myArray = for i = 1 to 1000 collect #(random 0 10, random 0 10, random 0 10)
	
	QArray = ArrayQuery myArray
	QArray.useComparer(true)
	QArray.setComparer "SumArrayComparer" 
	
	t1 = timestamp()
	kk = (QArray._where(#'x => Comparer._Value x < 15')).sortDES()
	t2 = timestamp()
	format "Sort Descending elements whose Value is Less than 15 = %
" kk
	format "time1= %ms
" (t2-t1)	-- 22ms for 1000 elements multiArray
)

Reserved for performance tests

test 1: ‘GroupBy’ (+50% time)

(
	myArray = for i = 1 to 1000 collect [random 0 100, random 0 100, random 0 100]
	
	QArray = ArrayQuery myArray
	QArray.useComparer(false)
	
	t1 = timestamp()
	groupedArray = (QArray.GroupBy(#'coord => coord.Y')).select()
	t2 = timestamp()
	format "Result = %
" groupedArray
	format "Result.count= %
" groupedArray.count	--	101 groups
	format "time1= %ms
" (t2-t1)				--	120ms for 1000 items
		
	t1 = timestamp()
				groupedArray = #()
				notFound = #{1..myArray.count}
				count = 0
				for i = 1 to myArray.count where notFound[i] do
				(
					count += 1
					append groupedArray #()
					append groupedArray[count] myArray[i]
					check = myArray[i].Y
					
					for j = i+1 to myArray.count where (notFound[j] and ((myArray[j].Y) == check)) do
					(
						notFound[j] = false
						append groupedArray[count] myArray[j]
					)
				)
	t2 = timestamp()
	format "Result = %
" groupedArray
	format "Result.count= %
" groupedArray.count	--	101 groups
	format "time1= %ms
" (t2-t1)				--	81ms for 1000 items
)

120ms vs 81ms (148% time) for 1000 items
253ms vs 168ms (151% time) for 2000 items

Reserved for updates

09/01/2017:

  • added Query Function ‘GroupBy’: create multiArray of groups following lambda expression criteria.
  • added Final Function ‘Average’: returns the mean of the query
  • added Final Function ‘SortByIndex’: returns the sorted array based on n’th element’s value
    10/01/2017:
  • added Query Function ‘maxObjectQuery’: allows to use a <MaxObject> for the query

I wonder whats the purpose behind of doing this ? I dont see this will speed up workflow of doing thing in ms-ing, a riddle scripting, or is this to make me got headache,maybe?

1 Reply
(@aaandres)
Joined: 11 months ago

Posts: 0

Thanks for posting, k4noe.
The purpose is, effectively, speed up workflow. Have you tried it? As functions are predefined, you can save time of coding. And performance is good enough for most purposes.
Of course it’s a new set of instructions that we have to learn and explore. That can be a little headache if you’ve never worked with lambda expressions. But it can finally get useful. I’m sure.

i don’t see a big reason to do ‘lambda style’ mxs coding, but if i would do:

that’s how i’d do it:

fn _one_arg_execute act a = act a 
_one_arg_execute (fn'' a = "_" + a as string) 4 

fn _two_arg_execute act a b = act a b 
_two_arg_execute (mapped fn'' i a = format a i) #(1,2,3) ">> %
"



it looks pretty clear for me, and doesn’t need ‘pre-compilation’ or ‘parsing’

the most interesting implementation for ‘lambda’ could be any ‘mapped’ tasks:

fn _three_arg_execute act a b c = (c = act a b c) 

(
	delete objects
	sp = converttomesh (geosphere())
	ii = #()
	_three_arg_execute (mapped fn'' i mesh list = (if (getvert mesh i).z < 0 do append list i; list)) (#{1..sp.numverts} as array) sp ii
	sp.selectedverts = ii
)




1 Reply
(@aaandres)
Joined: 11 months ago

Posts: 0

I absolutely agree with you. And I haven’t implemented it.
With actual code, we could do:

(
	delete objects
	sp = converttomesh (geosphere())
		
	QArray = ArrayQuery (#{1..sp.numverts} as array)
	ii = (QArray._Where(#'vert => (getvert $GeoSphere001 vert).z < 0')).select()
	sp.selectedverts = ii
)

or…

(
	delete objects
	sp = converttomesh (geosphere())
		
	QArray = ArrayQuery (for v = 1 to sp.numverts collect (getvert sp v))
	ii = QArray.FindAllIndex(#'vert => vert.z < 0')
	sp.selectedverts = ii
)

or…

(
	delete objects
	sp = converttomesh (geosphere segments:20)

	QArray = ArrayQuery #(sp)
	ii = ((QArray.Change(#'node => for v = 1 to node.numverts collect (getvert node v)')).Change(#'verts => for v= 1 to verts.count where verts[v].z<0 collect v')).Select()
	sp.selectedverts = ii[1]
)

The problem I see with your proposal is the ‘query of query’. Imagine that, it’s not pretty clear:

b=#(); _two_arg_execute (mapped fn'' i a = format a i) (_two_arg_execute (mapped fn'2' c b= append b (c*2)) #(#(1,2,3), #(4,5,6), #(7,8,9)) b; b)  ">> %
"


Just for test, with a geoSphere with 20 segments (4002 verts):

  • Your mapped function: 9ms
  • First query method: 18ms
  • Second query method: 13ms
  • Third query method: 9ms
Page 1 / 2