Possible to sort multiple parallel collections together?

If I have multiple, parallel collections, is there a Collection member function to sort them together?
Like this:
SortCollections($LastName_col;$FirstName_Col)

Why you have two collections?

I could have 100.
I want like a “MULTI SORT ARRAY” for collections.
So, it could be SortCollections($CollectionOfCollections;$SortOrders)

If one does NOT exist, then I’ll write my own.

You should change your code to not have 100 arrays, you should have one collection with objects. Programming is much easier then.

1 Like

ok: so since there is NOT a function to do this: I wrote one: and I’m posting it here.

This function will sort the actual source collections: even if they contain complex structures.

  //BB_Collections_Sort(Object)
  //By: Tony Ringsmuth 06/10/20, 17:26:46

  //FUNCTION: 
  // Like 4D's "MULTI SORT ARRAY", but for collections.
  //--------------------------------------------------------------------------------
  //PARAMETERS
  //$1: Object: propties:
  //      collectionsOb:  an object of collections to be ordered
  //      criteria: the ordering criteria:  see https://doc.4d.com/4Dv18/4D/18/collectionorderBy.305-4505869.en.html
  //         criteria Example: ("Last_Name, First_Name") or ("Last_Name desc, First_Name asc")

  //--------------------------------------------------------------------------------
  //REVISION HISTORY
  //06/10/20: New

  //--------------------------------------------------------------------------------

C_OBJECT($1)

C_OBJECT($Collections_ob)
$Collections_ob:=$1.collectionsOb  //a collection: the list of collections


  //$SuperCol will be one collection, with the same number of rows as the many collections
  //  where each row will be an object containing properties: that are from the table of collections
C_COLLECTION($SuperCol)
$SuperCol:=New collection


ARRAY TEXT($aPN;0)
OB GET PROPERTY NAMES($Collections_ob;$aPN)

C_LONGINT($MaxLen_i;$Len_i;$ii;$Row_i)
$MaxLen_i:=-1
For ($ii;1;Size of array($aPN))
	If (Value type($Collections_ob[$aPN{$ii}])=Is collection)
		$Len_i:=$Collections_ob[$aPN{$ii}].length
		If ($Len_i>$MaxLen_i)
			$MaxLen_i:=$Len_i
		End if 
	End if 
End for 

If ($MaxLen_i>-1)
	For ($Row_i;1;$MaxLen_i)
		$SuperCol[$Row_i-1]:=New object
	End for 
	
	C_TEXT($PN_t)
	C_COLLECTION($Col_c)
	
	For ($ii;1;Size of array($aPN))
		$PN_t:=$aPN{$ii}
		If (Value type($Collections_ob[$PN_t])=Is collection)
			$Col_c:=$Collections_ob[$PN_t]
			For ($Row_i;1;$Col_c.length)
				$SuperCol[$Row_i-1][$PN_t]:=$Col_c[$Row_i-1]
			End for 
		End if 
	End for 
	
	$SuperCol:=$SuperCol.orderBy($1.criteria)
	
	  //Our "super collection" is now sorted: 
	  //  put it's items back to the original collections in the new order
	For ($ii;1;Size of array($aPN))
		$PN_t:=$aPN{$ii}
		If (Value type($Collections_ob[$PN_t])=Is collection)
			$Col_c:=$Collections_ob[$PN_t]
			For ($Row_i;1;$Col_c.length)
				$Col_c[$Row_i-1]:=$SuperCol[$Row_i-1][$PN_t]
			End for 
		End if 
	End for 
	
End if 

Here’s an example of how it can be used:

C_OBJECT($Es)
$Es:=ds.Person.query("ID < 100")

C_COLLECTION($LN_c;$FN_c;$ID_c)
$LN_c:=$Es.Last_Name
$FN_c:=$Es.First_Name
$ID_c:=$Es.ID

$ResEnt_c:=New collection  //This is just to show that we could also "bring along for the ride" collections of any content.
For ($ii;1;$Es.length)
	$ResEnt_c[$ii-1]:=$Es[$ii-1]
End for 

$Cols_ob:=New object(\
"Last_Name";$LN_c\
;"First_Name";$FN_c\
;"ID";$ID_c\
;"SourceEntity";$ResEnt_c\)

BB_Collections_Sort (New object("collectionsOb";$Cols_ob;"criteria";"Last_Name asc, First_Name"))

What do you mean by “parallel collections”?

Could you provide a short example of the data?

Hi,

I am not sure to understand why you need separated collections.

You can easily get a collection of objects by doing something like this:

$coll:=ds.Person.query("ID < 100").orderBy("lastname, firstname").toCollection("ID, firstname, lastname")

You’ll get a collection of objects with properties: ID, lastname, firstname

If you really need separated sorted collections, you can do something like this:

$fn:=ds.Person.query("ID < 100").orderBy("lastname, firstname").firstname
$ln:=ds.Person.query("ID < 100").orderBy("lastname, firstname").lastname

You’ll get 2 collections of Strings

Jeremy,

What do you mean by “parallel collections”?
I mean like what we’ve done in traditional 4D with parallel arrays.
Like

SELECTION TO ARRAY([Person]First_Name;$aFN;[Person]Last_Name;$aLN)

…except with collections.
HOWEVER: for my interest: I have cases where I receive the data from ~somewhere~ (not necessarily records) as separate collections: and now I want to sort the collections together - without combining them.
That’s my business case.

Marie-Sophie,
I totally understand that if I’m collecting my data directly from entity selections, that I can order my entity selection first, and then get my collections.
However, I"m starting with a case where my collections do NOT come from an entity selection.
I’ve written my code to sort the collections together (see my earlier post).
It seems to me that as developers upgrade legacy systems, they’ll have a need for this kind of functionality. The code that I wrote will do the job.

Hi Tony,

Perhaps the easiest in your case is to use arrays. You can always turn your array into a collection with ARRAY TO COLLECTION if you really need a collection at the end.

1 Like

I think I had the same problem, a few months ago: part from data, part from a json file, to be “synchronised”. Supposing I can remember where I encountered that, I won’t forget where is your code :wink:

Fabrice,
Thanks for your suggestion: transferring them to arrays could cause a loss of precision.

The method that I created (and listed in this post) is working well: and has no loss of precision.
The collections that it sorts could contain anything that collections can hold: including entity references: and possibly mixed data types. That would be more difficult with arrays.