Home > Blockchain >  Calculate average from MutableCollection<Any!>?
Calculate average from MutableCollection<Any!>?

Time:12-12

I have just started utilizing a Firestore server to store values from my android app. I have retrieved these values and now want to calculate an average from them. My original Idea was to get the values, convert them to a float (there are decimals so I am guessing this is the best format) and then calculate an average to display. However parts of this isn't working so I am wondering if there is a more optimal way.

Current code:

val map = document.data?.values //gets values from the hashmap
Log.d("firestore", "values1 = $map")
val map2 = map.toString() //converts them to string
Log.d("firestore", "values2 = $map2")
val map3 = map2.toFloat() //converts them to a float??
Log.d("firestore", "values3 = $map3")

The float section also returns random digits, for example the string is [5.0, 5.0] and the float returns [91.0, 53.0, 46.0, 48.0, 44.0, 32.0, 53.0, 46.0, 48.0, 93.0]. Any help on how I could convert the values so I can calculate the average of the values, would be much appreciated!

CodePudding user response:

Can you provide the input (document.data) and the actual log output? It would help your understanding just as much anyone offering answer also to see the Kotlin inferred data types.

I assume the first variable map is MutableCollection<Any!> from your question. Calling it map is misleading since map is a key/value construct that requires two types to describe it.

When you call toString() on a Collection you are going to get a String representation. So I can believe the output is indeed [5.0, 5.0]. It then makes no sense trying to convert that to float, as this whole string is not a float.

You are going about this the wrong way.

First you need to convert the Collection<Any!> into a strongly typed array so you can do proper maths on it.

Let's start with some data we can see

val source : MutableMap<String, Any> = mutableMapOf("n1" to 2.0, "n2" to 3.5, "s1" to "fish", "n3" to 4.5)
val listOfAll: MutableCollection<Any> = source.values
println("listOfAll=$listOfAll")

This produces

listOfAll=[2.0, 3.5, fish, 4.5]

We can't perform calculations, so let's just filter out anything that is not a number

val listOfOnlyNumbers = listOfAll.filterIsInstance<Number>()
println("listOfOnlyNumbers=$listOfOnlyNumbers")

This produces

listOfOnlyNumbers=[2.0, 3.5, 4.5]

Now there is an in-built average function but Number is abstract so we need cast to a concrete class. Float would do, but most would normally use Double (lower precision than Float). If these values are Decimal in origin BigDecimal is better as it is optimised for decimals so you don't get 12.340000000000001 kind of thing.

val listOfDoubles = listOfOnlyNumbers.map { it.toDouble() }
val average = listOfDoubles.average()
println("average=$average")

Which produces what you may want

average=3.3333333333333335

(taking care that the original collection had one more value which is not taken into consideration for the average division)

So in summary what you want comes down to

val average = document.data?.values
   .filterIsInstance<Number>()
   .map { it.toDouble() }
   .average()
  • Related