I am trying to convert a traditional map:
1 -> "YES",
2 -> "NO",
3 -> "YES",
...
To a list of maps with fixed keys like such:
[
<number -> 1,
answer -> "YES">,
<number -> 2,
answer -> "NO">,
...
]
Right now I have a solution which does not look good and is not really making use of Kotlin's functional features. I was wondering if there was a clearer solution that did:
fun toListOfMaps(map: Map<Int, String>): List<Map<String, Any>> {
val listOfMaps = emptyList<Map<String, Any>>().toMutableList()
for (entry in map) {
val mapElement = mapOf(
"number" to entry.component1(),
"answer" to entry.component2()
)
listOfMaps.add(mapElement)
}
return listOfMaps
}
Just to use Map#map is sufficient for you, for example:
fun toListOfMaps(map: Map<Int, String>): List<Map<String, Any>> {
// v--- destructuring `Map.Entry` here
return map.map { (number, answer) ->
mapOf("number" to number, "answer" to answer)
}
}
Related
I've got the task to write a function using fold (functional programming) to count the number of elements in a list that fulfill the predicate. I was given the function signature fun <A> count(list<A>, predicate: (A) -> Boolean): Int. Fold shall not only be used as iteration, but also generate the return value. So I tried to do this:
fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
return list.fold(0) {
acc, a ->
if (predicate(a)) {
return acc + 1
}
return acc
}
}
I wrote a println to check if it works:
println(count3(listOf (1, -2, 3, 10, -5, 8, 12), { it > 0 && it < 10 }))
However, I got the result 1 instead of 3 on the console and I don't know where the fault is. So, does anyone have an idea where my error is or how I can implement the function instead?
And just to be clear: Fold accumulates a value, starting with the initial value (in this case 0) and applying the operation from left to right to the current accumulator and each element or am I mistaken?
EDIT (I hope it's okay to edit a question instead of asking a new one):
Is it possible to return a whole list instead of just an int? I just found examples returning integers or booleans. What I tried:
I've used the same function signature from above. But instead of return an Int, I want to return a list:
fun <A> returnList(list: List<A>, predicate: (A) -> Boolean): List<A> {
return list.fold(mutableListOf()) {
acc, a ->
if (predicate(a)) {
acc.add(a)
} else {
acc
}
}
}
The problem that I found is that acc.add(a) returns a boolean and not a list, so that the IDE marks it as a mistake. So is there a way to return a list?
Thanks in Advance.
By saying return you return the entire count function. you can use return#fold instead. so like
fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
return list.fold(0) {
acc, a ->
if (predicate(a)) {
return#fold acc + 1
}
return#fold acc
}
}
alternatively and maybe better is to do it like this
fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
return list.fold(0) {
acc, a ->
if (predicate(a)) {
acc + 1
} else {
acc
}
}
}
the last expression in a lambda is implicitly also its return value
Try it like this:
fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
return list.fold(0) { acc, a -> if (predicate(a)) acc+1 else acc }
}
fun main(args: Array<String>) {
val x = listOf<Int>( 1, -2, 3, 10, -5, 8, 12);
println(count(x, { it > 0 && it < 10 }))
}
Looking at this site made the necessary change clear to me.
Is that form necessary because fold uses tail recursion? Interesting to see what the reason is.
fun <A> count(list: List<A>, predicate: (A) -> Boolean): Int {
return list.fold(0) { acc, a -> acc + predicate(a).run { if (this) 1 else 0 } }
}
I found the answer how to return a list (see my question edit) with fold in the kotlin-forum:
Instead of writing:
fun <A> returnList(list: List<A>, predicate: (A) -> Boolean): List<A> {
return list.fold(mutableListOf()) {
acc, a ->
if (predicate(a)) {
acc.add(a)
} else {
acc
}
}
}
You can write (the following solution was provided by al3c in the kotlin forum):
fun <A> returnList(list: List<A>, predicate: (A) -> Boolean): List<A> {
return list.fold(mutableListOf()) {
acc, a ->
if (predicate(a)) {
acc.add(a)
}
acc
}
}
By doing so, the code returns not a single integer, character or boolean, but the whole list.
I have this function that from two lists, I want it to construct a HashMap:
def storeHashmap(
keys: List[List[Option[String]]],
similarities: List[Float]
): List[HashMap[Float, (String, String)]] = {
for ((k, s) <- (keys.zip(similarities)))
yield HashMap(s -> (k.head.get, k(k.length - 1).get))
}
Instead of returning HashMap[Float, (String, String)], it returns List[HashMap[Float, (String, String)]
What am I missing? I don't want to use reduce at the end! I want to concatenate the hashMap according to iterations for its construction
def storeHashmap(
keys: List[List[Option[String]]],
similarities: List[Float]
): Map[Float, (String, String)] = {
val yieldOutput = for ((k, s) <- keys.zip(similarities))
yield s -> (k.head.get, k.last.get)
yieldOutput.toMap
}
I have a list of two-item lists:
def list = [[key1, value1], [key1, value1], [key2, value1], [key2, value2], ...]
I am trying to write Groovy code which will take "list" and return another list, which displays not only the frequency of each duplicate, two-item list, but also if there are items which are unique:
def newList = [[key1, value1:2], [key2, [value1:1, value2:1]], ...];
The reasoning behind this format is because I'd write more code to throw an error if a specific "key" had more than one "value". If there is an easier way to do this, any help/suggestions would be appreciated.
It normally helps if you show what you've tried when asking a question here...
In this case though, you just need:
def result = list.groupBy { it[0] }
.collect { k, v -> [k, v.countBy { it[1] }] }
And result will equal:
[['key1', ['value1':2]], ['key2', ['value1':1, 'value2':1]]]
You could also do something like this:
def result = list.groupBy { it[0] }
.collectEntries { k, v -> [k, v*.getAt(1).unique().size() ] }
To give you:
['key1':1, 'key2':2]
I have a list of tuples:
val t = List( (1,2,1.0), (1,3,2.0), (1,2,1.1) )
I want to create a map with t._1 as the key, and as the value a map with t._2 as the key and the sum of t._3 as the value.
val m = Map( (1-> Map((2 -> 2.1), (3 -> 2.0)) )
How can I do this in Scala?
I'd like to accomplish this with pure Scala as opposed to a library, but if a library such as scalaz etc. is (in my completely subjective opinion) a nicer looking solution, I would accept that answer as well.
If you are into one-liners then you might like this:
val t = List( (1,2,1.0), (1,3,2.0), (1,2,1.1) )
t.groupBy(_._1).mapValues(_.groupBy(_._2).mapValues(_.map(_._3).sum))
Result is:
Map(1 -> Map(2 -> 2.1, 3 -> 2.0))
Here's one way:
t.groupBy(_._1).map {
case (outerKey, outerList) =>
outerKey -> outerList.groupBy(_._2).map {
case (innerKey, innerList) =>
innerKey -> innerList.map(_._3).sum
}
}
yields:
Map(1 -> Map(2 -> 2.1, 3 -> 2.0))
I have the following types:
type ColorCounter =
{
Count : int
Color : Microsoft.Xna.Framework.Color
}
let AvailableColors : Map<uint32,ColorCounter> = .....
I would like to iterate through the Map and return a List . I wrote the following function that doesn't compile:
let AvailableColorList(map : Map<uint32,ColorCounter>) : List<Microsoft.Xna.Framework.Color> =
let colorSeq = seq {
map |> Map.iter (fun key col -> yield col.Color)
}
colorSeq |> Seq.toList
I guess I'm doing something wrong with the syntax of the function passed to iter, but I've not find any suitable example that shows me how to do that.
Could anyone help me?What's my error? How can I fix the code above?
I think you want this
let AvailableColorList(map : Map<uint32,ColorCounter>) =
ResizeArray(map |> Seq.map (fun (KeyValue(_, col)) -> col.Color))
You're mixing a sequence comprehension and map, which are two different ways of doing the same thing.
You could also write it this way
let AvailableColorList(map : Map<uint32,ColorCounter>) =
ResizeArray([ for KeyValue(_, col) in map -> col.Color ])
let AvailableColors : Map<uint32,ColorCounter> = Map.empty
let colors = [ for (KeyValue(_, v)) in AvailableColors -> v ]