0

I have model object which has an Map of array lists.

data class ResponseModel(
    val schedule: Map<String, ArrayList<String>>,
    val target_temp: String

)

This is successfully parsing the data coming from the api sample data looks like below.

{
    "limit": "10",
    "schedule": {
        "0": ["0", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"],
        "1": ["1", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"],
        "2": ["2", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"],
        "3": ["3", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"],
        "4": ["4", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"],
        "5": ["5", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"],
        "6": ["6", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"]
    },
    "target_temp": "32.18"
}

I can access the individual array values as per key in my schedule, with the following code.

holder?.view?.start?.text = responseModel.schedule.get("0").toString()

This gives me desired results

["0", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"]

Now I want to count how many elements are in the above extracted array. To achieve that I tried creating another array of elements from above and then performed both count and size functions. However, this did not work.

arrayOf(responseModel.schedule.get("0")).count()
Zoe
  • 27,060
  • 21
  • 118
  • 148
humble_pie
  • 119
  • 10
  • Can't you use `size()` from ArrayList ? – Maxouille Mar 26 '19 at 14:35
  • I'm not sure what `get` returns, but you get one of two: Either a JSON object for whatever library/framework/class you're using, or an array. That lands you with a 1-size `Array` or `Array>` (unless auto-unpacking is a thing, but you didn't specify`*`) – Zoe Mar 26 '19 at 14:37
  • @Maxouille no size() does't work oddly – humble_pie Mar 26 '19 at 14:41

3 Answers3

3

Based on your code, I'm going to assume you've completely parsed it into a Map<K, V>. If you have, the reason is extremely easy to find: You've added an Array(/List) to an Array. Which means your attempt gives you an Array<Array<String>> or Array<List<String>>.

If you again take a look at your code, you only add one item, or one array to the array. If you parse it back to JSON, it looks like this:

[
    [
        "0", "3.00", ...
    ]
]

Basing off the JSON example, here's a pseudocode-ish example of your current code:

[
    [
        "0", "3.00", ...
    ]
].size()

Which naturally returns 1: you only have one item in the parent.

If you wanted it to work exactly the way you currently have it, you'd have to use the spread operator (*). arrayOf takes a vararg, and you have to spread the original array to the vararg to not pass an array. That lands you with an Array<String> (or possibly Array<Any> depending on the map):

arrayOf(*responseModel.schedule.get("0")).count()

I do not recommend this approach - it's overkill in your case, and will reduce performance. I'm mentioning it because it's a solution.

As Boken has already mentioned, you don't need to wrap it in an Array at all. If you store it as a Map, you already have a List or Array and you can access it incredibly simply with responseModel.schedule.get("0").size.

If you store it as Any (which I assume you do), you'll have to add an additional step:

val cache = responseModel.schedule.get("0"); // Any, in reality Array<String>/Array<Any>/List<Any>/List<String>
if (cache is Array) println(cache.size)
else if(cache is List) println(cache.size)

The casting here is to get automatic type inference - if you have an Any, the compiler doesn't know if it has a size field, and it will therefore throw an exception.

You can, of course, cast it directly, but that isn't a good idea if you ever end up with different input (intentionally or accidentally)


If, however, you don't actually store it in the form of a map, that complicates matters. To keep up with the first part, you'd have an Array<JSONObject>, and you only have one JSONObject in the array.

Unlike the last part, you can't use the spread operator and get it straight into an Array (which, again, I don't recommend you use unless you have to)

If you store a JSONObject for whatever system you use, it might have a size/length field/function that you can use, and it's not as complicated. Otherwise, you'll need to get an array/list from the JSON object, and run the length on that. I'd show you code for this part, but without knowing what you use (built-in, Jackson, Gson, etc), I don't have enough details to show any code. Nevertheless, the idea is still getting the size directly from the JSONObject, or getting an Array which you can run the size on instead.


Further reading

Zoe
  • 27,060
  • 21
  • 118
  • 148
1

Wrapping map with arrayOf(...) you are creting new structure - array containing lists.

You have to change it from:

arrayOf(responseModel.schedule.get("0")).count()

to:

responseModel.schedule["0"]?.size
// or
responseModel.schedule["0"]?.count()

Full example:

fun main() {
    val schedule = mapOf(
        "0" to listOf("0", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
        "1" to listOf("1", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
        "2" to listOf("2", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
        "3" to listOf("3", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
        "4" to listOf("4", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
        "5" to listOf("5", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
        "6" to listOf("6", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59")
    )

    println(schedule["0"])
    // output:  [0, 3.00, 7.59, 9.00, 12.59, 14.00, 22.59]

    println(schedule["0"].count())
    // output:  7
    // because you have list with 7 elements

    println(arrayOf(schedule["0"]).count())
    // output:  1
    // because you have array with 1 element - you have array of lists
}
Boken
  • 4,825
  • 10
  • 32
  • 42
0

Problem:

arrayOf(responseModel.schedule.get("0")).count()

will create a list with a list as only element. That's why count will return 1.

Solution:

Given your data looks like this after parsing:

val responseModel = ResponseModel(
        schedule = mapOf(
                "0" to arrayListOf("3.00", "7.59", "9.00", "12.59", "14.00", "22.59"),
                "1" to arrayListOf("1", "3.00", "7.59", "9.00", "12.59", "14.00", "22.59")
                // ...
        ),
        target_temp = "32.18"
)

each element of schedule will be an ArrayList for which you can determine the size like this:

val numElements = responseModel.schedule["0"]?.size

Note:

  • You can use the get operator notation [] instead of calling it as a function:

    val firstLinesValues = responseModel.schedule["0"]
    
  • Please use camel case for your variable names (target_temp -> targetTemp) since it is a convention.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121