Collections Functions - Gnorion/BizVR GitHub Wiki

Collections

image

Basic Collections

There are three basic collections.

  1. The basic collection is often called a bag. It stores objects with no ordering of the objects and no restrictions on them.
  2. Another unstructured collection is a set where repeated objects are not permitted: it holds at most one copy of each item. A set is often from a predefined universe.
  3. A collection where there is an ordering is often called a list. Specific examples include an array, a vector and a sequence.

Collections

  • Collections are a bunch of objects that can be named and referred to.
  • Different types of object can be grouped into a single collection.
  • Objects in a collection can be basic data types, or structured data types or even collections.
  • Special operations are available for processing collections
  • The members of a collection do not even have to be of the same type. example {'red','red',3.24,'2022/12/31',T,{1,2,{'a','b',5}},'red'} is a collection

Sets

  • Sets are collections of objects that contain no duplicates
  • The objects in a set are called its elements or members.
  • The elements in a set can be any types of objects, including sets!
  • The members of a set do not even have to be of the same type. Example {'red',3.24,'2022/12/31',T,{1,2,{'a','red',5}}}is a set

Lists

  • Lists are collections of objects that have been arranged into a specific sequence

Operations on Collections

  • A collection can be sequenced on one or more attributes using .sortedBy or .sortedByDesc
  • An operation can return any data type including a collection.

General structure can be

{<element> in <Collection> | <predicate>}.<operation> when operation applies to the collection as a whole or

{<element> in <Collection> | <predicate>}.<property>.<operation> when the operation applies to an attribute of the collection. . may be repeated arbitrarily

Sets are sometimes defined using this notation {x : x ∈ N, 3 <= x <= 4}

  • this is equivalent to {x in N where x in [3..4]} which is an infinite set if x is real or the set {3,4} if x is integer.
  • this is equivalent to {x in N where x>=3, x<=4]}
  • its also equivalent to {x in {3,4}} when x is integer

Multiple collections can be joined and filtered. Note: In place of | you can also use "where" or "filter"

Example Explanation
{color in (red,green,blue},number in {1,2,3,)} would generate the cross product of 9 tuples of the form <color,number>. i.e. (red,1), (red,2),(red,3),(green,1),(green,2),(green,3),(blue,1),{blue,2),(blue,3)
{p in Persons, c in Cars where p.colorPref=c.color } would produce a collection of tuples <p,c> where the car has a color the person prefers

NOTE: As you go from left to right in the expression you are getting more and more specific

Example: Generating cross products

Business Question Possible Implementation Return Value
Is there any person over 65? notEmpty({p in Person where age>65}) returns T or F
Are there any persons between 13 and 19? notEmpty({p in Person where age in [13..19]}) returns T or F
Are there more than 2 persons between 20 and 65? size({p in Person where age in [20..65]}) > 2 returns T or F
How many persons between 20 and 65? n=size({p in Person where age in [20..65]}) sets the value of n
Find males under 13 mu13={p in Person where age<13, gender='male'} creates a collection named mu13
Are all the people over 65 male? allContains({p in Person where age>65},'gender','male') returns T or F ??????
Are there any males over 65 ? notEmpty({p in Person where age>65,gender='male'}) returns T or F
Are there any non-males over 65? notEmpty({p in Person where age>65,gender<>'male'})
What is the highest income for males over 65? highest={p in Person where age>65,gender='male'}.income.max
Is the youngest person over 65 a male? {p in Person where age>65}.sortedBy(age).first.gender = 'male' returns T or F
What is the sum of incomes for people over 65 incomeSum={p in Person where age>65}.income.sum returns the sum of incomes
Is the lowest income for over 65s greater than zero? {p in Person where age>65}.income.min >0 returns T or F
What is the average age of the oldest 3 males between 21 and 45? avgAge={p in Person where age in [20..65],gender='male'}.sortedBy(age).first(3).age.avg returns a number
Which are the oldest 3 males between 21 and 45? oldest={p in Person where age in [20..65],gender='male'}.sortedBy(age).first(3) collection saved for later use
What is the sum of the incomes for the oldest N males? incomeSum={p in Person where gender='male'}.sortedByDesc(age).first(N).income.sum returns a number
What state does the youngest person over 65 live in? state={p in Person where age>65}.sortedBy(age).first.state
Find all the males over 65. seniorMales={p in Person where age>65,gender='male'} collection saved for further use
Then find their average income. seniorMaleAvgIncome=seniorMales.income.avg result is a value
Is the highest income of the oldest 5 persons greater than 10000? {p in Person}.sortedBy(age).first(5).sortedByDesc(income).first.income>10000
Is person with the lowest income over parm.x a parm.gender {p in Person where income>parm.x}.sortedBy(income).first.gender=parm.gender
Is there a male over 65? {p in Person where age>65}.exists(gender='male') returns true or false
or alternatively {p in Person}.exists(gender='male',age>65) returns true or false
or alternatively {p in Person where gender='male',age>65}.size>0 returns true or false
.
Find the sum of the two lowest book prices lowest_two=Books.sortedBy(price).at(1).price+Books.sortedBy(price).at(2).price returns a number
or lowest_two=Books.sortedBy(price).first(2).price.sum
or lowest_two=Books.sortedBy(price).subSequence(1,2).price.sum

NOTE
avgAge={p in Person where age in [20..65],gender='male'}.sortedBy(age).first(3).age.avg can be expressed as a series of statements:

  1. adultMales={p in Person where age in [20..65],gender='male'}
  2. adultMalesAscendingAge=adultMales.sortedBy(age)
  3. youngestThreeAdultMales=adultMalesAscendingAge.first(3)
  4. avgAge=youngestThreeAdultMales.age.avg

Person.iterate() Eg {p in Person}.iterate(p.net=p.gross-p.taxes) updates p.net for all persons

Basic Collection Operators

size, iterator(), add() or +=, remove() or -=, clear

Single Collection operators

Operation Example Result
.exists {p in Person where age>65}.exists(gender='male') true if any p over 65 is male
.forall {p in Person where age>65}.forAll(gender='male') true if all p over 65 are male
.isEmpty {p in Person where age>65}.isEmpty true if there are no p over 65
.notEmpty {p in Person where age>65}.notEmpty true if there is at least one p over 65
.size {p in Person where age>65}.size returns the number of p over 65
.sortedBy {p in Person where age>65}.sortedBy(age) the set of p over 65 in ascending age
.sortedByDesc {p in Person where age>65}.sortedByDec(age) the set of p over 65 in descending age

Sequenced Collection operators

Collection must be sorted eg sortedCollection=collection.sortedBy(age)

Operation Example Return
.at(n) {p in Person where age>65}.sortedBy(age).at(1) returns the youngest p over 65
.first(n) {p in Person where age>65}.sortedBy(age).first returns the youngest p over 65
.last(n) {p in Person where age>65}.sortedBy(age).last(2) returns the oldest 2 p over 65
.subSequence(i,j) {p in Person}.sortedBy(age).subSequence(2,Person.size-1) returns all but the youngest and oldest p

Multiple Collection operators (Collections are of the same type)

Assume A={red,green,blue} and B={red,yellow,blue,purple} where A and D are sets of instances of the same type

Operation Example Result Explain
union C=A+B C={red,green,yellow,blue,purple} what is in A and B combined. A+B=B+A
union (alt) union(A,B
intersection C=A@B C={red,blue} what is common to both A and B. Note A@B=B@A
intersection (alt) intersection(A,B)
difference C=A-B C={green} what is in A but not B. A-B<>B-A
difference C=B-A C={yellow,purple} what is in B but not A.
difference C=(A+B)-(A@B) C={yellow,green,purple} what is not in both A and B. Also C=(A-B)+(B-A)
difference C=(A@B)-(A+B) C={} always the empty set.
difference (alt) difference(A,B)

Multiple Collection operators (Collections may be of different type)

Each should implement a common interface Common attributes (if any) must be of the same type. Common methods (if any) may have different implementations but must return the same data type

Operation Example Explain
union transportation=cars+boats+planes merges three sets of different types into a single set with the combined attributes of all of them (effectively dynamic multiple inheritance)
union transportation={c in Cars where seats>4,insured=True}+(b in boats where type='hovercraft',seaworthy=True})+{p in Planes where age<5} merges three sets with filters

Attribute specific operators:

Operation Example Notes
.sum {1..100}.sum Sum of the first 100 integers
.sum {N..M}.sum Sum of the integers from N to M
.sum {n in 1..N where n.mod(2)=0}.sum Sum of the even numbers <= N
.sum {p in Person where age>65}.income.sum Sum of incomes of people over 65
.product {1..100}.product Product of the first 100 numbers
.max {p in Person where age>65}.income.max Largest income of people over 65
.min {p in Person where age>65}.income.min Smallest income of people over 65
.avg {p in Person where age>65}.income.avg Average income of people over 65
.allContain() {p in Person where age>65}.gender.allContain('male') equivalent to Person.forAll(age>65,gender='male')
.uniqueCount() {p in Person where age in [18..65]}.gender.uniqueCount Number of unique genders in persons 18..65

Filters (produce subsets of a collection)

[list of any valid expression involving attributes of the collection that evaluates to boolean]

{p in Person where age>65} just those instances where age >65.

Person is equivalent to Person[] and Person[*] meaning every instance of the class with no filtering. Person[n] any n arbitrary instances (can't think why we'd need this yet)

{p in Person where age>65,gender='male'} allows the filters to be applied in any order (perhaps even in parallel with the final result being the intersection of the two collections. This is equivalent to {{p in Person where age>65} where gender='male'} which requires the age filter to be applied first and then the gender filter is applied to the results. Not sure if it makes a huge difference

⚠️ **GitHub.com Fallback** ⚠️