Home > Mobile >  How to chain filter expressions together
How to chain filter expressions together

Time:07-21

I have data in the following format

ArrayList<Map.Entry<String,ByteString>>
[
  {"a":[a-bytestring]},
  {"b":[b-bytestring]},
  {"a:model":[amodel-bytestring]},
  {"b:model":[bmodel-bytestring]},
]

I am looking for a clean way to transform this data into the format (List<Map.Entry<ByteString,ByteString>>) where the key is the value of a and value is the value of a:model.

Desired output

List<Map.Entry<ByteString,ByteString>>
[
  {[a-bytestring]:[amodel-bytestring]},
  {[b-bytestring]:[bmodel-bytestring]}
]

I assume this will involve the use of filters or other map operations but am not familiar enough with Kotlin yet to know this

CodePudding user response:

It's not possible to give an exact, tested answer without access to the ByteString class — but I don't think that's needed for an outline, as we don't need to manipulate byte strings, just pass them around. So here I'm going to substitute Int; it should be clear and avoid any dependencies, but still work in the same way.

I'm also going to use a more obvious input structure, which is simply a map:

val input = mapOf("a" to 1,
                  "b" to 2,
                  "a:model" to 11,
                  "b:model" to 12)

As I understand it, what we want is to link each key without :model with the corresponding one with :model, and return a map of their corresponding values.

That can be done like this:

val output = input.filterKeys{ !it.endsWith(":model") }
                  .map{ it.value to input["${it.key}:model"] }.toMap()

println(output) // Prints {1=11, 2=12}

The first line filters out all the entries whose keys end with :model, leaving only those without. Then the second creates a map from their values to the input values for the corresponding :model keys. (Unfortunately, there's no good general way to create one map directly from another; here map() creates a list of pairs, and then toMap() creates a map from that.)

I think if you replace Int with ByteString (or indeed any other type!), it should do what you ask.

The only thing to be aware of is that the output is a Map<Int, Int?> — i.e. the values are nullable. That's because there's no guarantee that each input key has a corresponding :model key; if it doesn't, the result will have a null value. If you want to omit those, you could call filterValues{ it != null } on the result.

However, if there's an ‘orphan’ :model key in the input, it will be ignored.

  • Related