• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Ron McLeod
  • Jeanne Boyarsky
  • Paul Clapham
Sheriffs:
  • Tim Cooke
  • Liutauras Vilda
  • Junilu Lacar
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • fred rosenberger
  • salvin francis
Bartenders:
  • Piet Souris
  • Frits Walraven
  • Carey Brown

How to loop over Map<String, Array<Any>> in Kotlin?

 
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In my android app with Kotlin, I have a variable "data" type of Map>,Which Product is a kotlin data class.

Product data class contains var availableQuantities. I want to loop the Map> and conserve only the product with availableQuantities != 0, and update the data variable.How can I do this? Here's my code

But, after running the code an exception appear as the following image : enter image description here
The following image is the description of data :

Please help me, I'm really stuck
How can I correct my code to make it functionnal?
dataimg.png
[Thumbnail for dataimg.png]
 
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you want to keep your code functional, then you shouldn't modify the original map but produce a new map with the filtered data. It looks like you're trying to mutate the original data map though.

Just to make sure I'm clear on what your intent is, you want to have a Map<String, Array<Product>> where each Array<Product> contains only Product where availableQuantities > 0, correct?
 
Saloon Keeper
Posts: 12150
258
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The values in your data map are arrays, but the values in your filteredMap are lists. On line 7, you are trying to cast an Array to an ArrayList, which is not valid.

You must either convert the filtered array to an ArrayList first, or your filteredMap must use arrays as its value type.

P.S. in general it's not a good idea to use a specific type as ArrayList in type declarations. Use types such as Iterable, Collection or List instead.
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Something like this?

This is the output of that script:

shoes=[Product(name=Nike, qty=1)]
pants=[Product(name=Levis, qty=10), Product(name=Dockers, qty=5)]

You really should strive to stay functional in Kotlin and that means keep things immutable if at all possible. It's a big shift in mindset and the way you think about your program and program objects.
 
Maha Sakka
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Just to make sure I'm clear on what your intent is, you want to have a Map<String, Array<Product>> where each Array<Product> contains only Product where availableQuantities > 0, correct?


Yes
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you don't mind, a few comments on style.

Caveat: I've just recently started out with Kotlin myself so there may be better and more idiomatic ways than what I'm about to suggest below. That being said, I think I have a pretty decent handle on some of the Kotlin idioms.

1. Prefer val over var.

This leads to non-functional code:
Better:
You might also be able to keep your Product data class immutable as well:

although I'd have to see more details of how you're using it. Again, making Product immutable will require a shift in the way you're thinking about your program objects. Sometimes that's not easy to do. It seems to you have previously programmed in Java and have carried over some poor habits from working in Java.

2. As Stephan has already mentioned, avoid using specific implementations like HashMap and ArrayList. Even with Java code, you shouldn't be declaring any variables as ArrayList or HashMap. Those types belong on the right side. Declarations should use generic types, like List and Map. In Kotlin, it appears the idiom is to use the built-in factory methods like mapOf and arrayOf when possible.

3. Use type inference judiciously; declare explicit types for clarity and safety (to make sure you and the compiler are on the same page). Regarding type-safety and making sure you and the compiler are on the same page, there have been a few instances where I thought I was dealing with one type but the compiler interpreted what I had written as being of a different type. The compiler, of course, always wins in these type of situations so when in doubt, I'll explicitly declare the type I want to deal with so that I can help the IDE/compiler point out invalid expressions according to my intent, not what the compiler has inferred according to its inference algorithms.
 
Maha Sakka
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Something like this?

This is the output of that script:

shoes=[Product(name=Nike, qty=1)]
pants=[Product(name=Levis, qty=10), Product(name=Dockers, qty=5)]

You really should strive to stay functional in Kotlin and that means keep things immutable if at all possible. It's a big shift in mindset and the way you think about your program and program objects.



I try the following code but still didn't work

The data values is dynamic
 
Stephan van Hulst
Saloon Keeper
Posts: 12150
258
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
toTypedArray() only works for primitive arrays and for collections. Your dynamic type happens to be an array of reference types at runtime.

You need to either declare your filteredMap as a Map<String, Array<ProductData>> (then you don't have to perform any conversion on the dynamic value), or you need to declare it as Map<String, List<ProductData>> and then you need to call toList() on the dynamic value.
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Maha Sakka wrote:
I try the following code but still didn't work

The data values is dynamic


A couple of things:

1. "It didn't work" doesn't really tell us much. Please provide more details. Was there a runtime exception or a compiler error? Did you get unexpected results? Tell us exactly how things "didn't work."

2. Not sure what "data values is dynamic" has to do with any difficulties you're having.

Re #2, are you thinking that your context might be different because I was manually creating the map in the example I gave?

If so, that doesn't really matter. You're dealing with an abstract data structure, a Map, and the code doesn't really care about how that map was populated with values, nor should it. That's a key point in writing this kind of functional or even object-oriented code, you shouldn't have to care about the implementation, as long as the object adheres to the behavior defined by the interface you're programming to, you should be fine, regardless of where the data had come from.

If that isn't what you're referring to, then please clarify what you mean by "data values is dynamic" and what it has to do with being able to transform the original map to a filtered version of it.
 
Maha Sakka
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

1. "It didn't work" doesn't really tell us much. Please provide more details. Was there a runtime exception or a compiler error? Did you get unexpected results? Tell us exactly how things "didn't work."


An exception appear, exception java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.models.Product[]

Junilu Lacar wrote:

2. Not sure what "data values is dynamic" has to do with any difficulties you're having.

Re #2, are you thinking that your context might be different because I was manually creating the map in the example I gave?

If so, that doesn't really matter. You're dealing with an abstract data structure, a Map, and the code doesn't really care about how that map was populated with values, nor should it. That's a key point in writing this kind of functional or even object-oriented code, you shouldn't have to care about the implementation, as long as the object adheres to the behavior defined by the interface you're programming to, you should be fine, regardless of where the data had come from.

If that isn't what you're referring to, then please clarify what you mean by "data values is dynamic" and what it has to do with being able to transform the original map to a filtered version of it.


Dynamic, I mean it come from WS, and the values can be changed
Unfortunately, I haven't found a solution yet, I need your  help please
 
Stephan van Hulst
Saloon Keeper
Posts: 12150
258
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You've completely confused me now in what the data type of the incoming values are (yes, they are dynamic at compile-time, but what is their runtime type?) and what the type of the values is of the map that you're trying to convert the data to.

Please post the latest version of your code.
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Maha Sakka wrote:An exception appear, exception java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.models.Product[]


Ok, that makes sense because this:

does not match this:

This goes back again to using HashMap and ArrayList as your declared types. Stop doing that; it's going to get you more trouble than you know how to deal with. Stick with idiomatic Kotlin and use the generic Map, List, or Array types instead.

Rather, you should do this:



 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Maha Sakka wrote:Dynamic, I mean it come from WS, and the values can be changed


That the data comes from a web service is largely irrelevant as long as that data can still be unmarshalled to Product instances as you have defined them. Also, it doesn't matter that the values (I assume you're referring to the availableQuantities field) can change. If you're shooting for functional code, then it's better to start using functional semantics with immutable classes. Declaring the availableQuantities as a val or var is not related to being able to filter the data though. That's a totally different concern. The filtering doesn't care if the Product.availableQuantities field is mutable or not, only that it's at least readable.
 
Maha Sakka
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
First of all, I would like to thank you for your reply, thank you for your effort also
I try this code :

But, Unfortunately the same exception appear : exception java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.models.Product[]
I will put the value of data when debug, I don't know why this problem appear
Maybe the use of ws and ccoroutine ?


data.png
[Thumbnail for data.png]
datadetail.png
[Thumbnail for datadetail.png]
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The you've inadvertently misled us. Based on what you showed, the declaration should be:

I don't know why you keep insisting on using .toTypedArray() though.
 
Maha Sakka
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:


I try this code, but the same exception
About "toTypedArray()" it's a mistake
 
Junilu Lacar
Sheriff
Posts: 15801
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In your opening post, you wrote:

But subsequently, you've been referring to ProductData -- so what exactly does the data map contain? Could it be that line that's producing the error?

I mean should that in fact be this?

 
Stephan van Hulst
Saloon Keeper
Posts: 12150
258
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay, I'm going to assume that you will be converting your data to a Map<String, List<ProductData>>.

The deserialized data has runtime type LinkedHashTreeMap<String, ArrayList<LinkedHashTreeMap<String, String>>> however. Your problem is that you're trying to cast a LinkedHashTreeMap<String, String> to ProductData. Obviously this is not possible.

The REAL cause of your problem is that you're not using GSON properly. GSON can deserialize your data to Map<String, List<ProductData>> in one go, but you need to provide it the proper type tokens. Please show us the code where you're using GSON to deserialize the response from the web service.
 
Maha Sakka
Ranch Hand
Posts: 178
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:
But subsequently, you've been referring to ProductData -- so what exactly does the data map contain? Could it be that line that's producing the error?

I mean should that in fact be this?


It just a typo
 
Don't get me started about those stupid light bulbs.
    Bookmark Topic Watch Topic
  • New Topic