Average of a mixed list


#1

I am currently working on a refactor of a method I previously created
but have reached a snag. I want to replace a set of nested if statements
with a cleaner case statement.

The purpose of the method is to return the average value of a list,
it should support 5 different data types with different rules for each:

Real values are simply returned

Integer values are converted into Real values

Vector 2 and Vector 3 values are treated as the average of their axes

String values are treated as their length

This is the refactor as it stands now, along with my current issue:

This is an example of how it may be called, using every compatible data type:

From left to right -
Real, Integer, Vector2, Vector3, String
The result of this should equal to 1 but currently as all comparisons fail, the result is 0

I believe that this a scenario where the case statement cannot be used as, unlike class_of?, it does not explicitly compare the class of the item to each provided data type and instead treats each item generically.

Is what I am wanting achievable with a case statement or will I need to resort to using nested if statements like this?

Perhaps there is a better way than both of the above.


#2

I’ll see if I can get the case version to work in a bit, however you don’t need to nest if statements in SkookumScript - it supports multiple tests and clauses for a single if. :madsci:

Take a look at the Conditionals reference page in the SkookumScript online docs. Search or scroll down until you see the code example entitled “Multi-clause”.

So your code:

if this.class_of?(String) [item<>String.length]
else [if this.class_of?(Vector3) [item<>Vector3.avg]]

Can be written like this:

if class_of?(String) [item<>String.length]
 class_of?(Vector3)  [item<>Vector3.avg]
 // etc.

You can have as many tests and clauses as you like. No need to nest.


#3

Using a case statement works (2017-10-15):

// case version
// Should work, though case only uses
// instance version of = and needs to use
// class version (bug)
() Real
  [
  !total: 0.0

  do
    [
    total += case item.class
      Real    [item<>Real]
      Integer [item<>Integer>>Real]
      Vector2 [item<>Vector2.avg]
      Vector3 [item<>Vector3.avg]
      String  [item<>String.length>>Real]
      else    [0.0]
    ]
  total / length>>
  ]

You can also use a multi-clause if:

// if version
() Real
  [
  !total: 0.0
  
  do
    [
    !iclass: item.class
  
    total += if
      iclass = Real    [item<>Real]
      iclass = Integer [item<>Integer>>Real]
      iclass = Vector2 [item<>Vector2.avg]
      iclass = Vector3 [item<>Vector3.avg]
      iclass = String  [item<>String.length>>Real]
      else             [0.0]
    ]
  total / length>>
  ]

Let me know if this helps and makes sense and if you have any additional questions.


SK equivalent to TSubclassOf and BlueprintPure
#4

Thank you very much for the help Noolarch!
My method now works as I wanted it to, the multi-clause aspect of SK really helps in making my method easily readable and expandable. :grin:


#5

Using classes in a case expression now works properly in the runtime.

It will be available in the next update - hopefully sometime this week.