Average of a mixed list


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.


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.


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

    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
    !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

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:


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

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