How would one go about writing a function from an object to a Map:
function objectToMap<K, V>(transformKey: string => K, obj: {[key: string]: V}): Map<K, V> {
const map = new Map()
const entries = Object.entries(obj)
for (const [k, v] of entries) {
map.set(transformKey(k), v)
}
return map
}
The problem seems to be that the return type of Object.entries is Array<[string, mixed]>. (See the error below).
Cannot return map because mixed [1] is incompatible with V [2] in type argument V [2].
<somePath>/index.js
145| map.set(transformKey(k), v)
146| }
147|
148| return map
149| }
150|
151| function makeProficiencyWithProgress(
/private/tmp/flow/flowlib_149a8c8/core.js
[1] 54| static entries(object: $NotNullOrVoid): Array<[string, mixed]>;
Related
I was looking through array extension functions and found reduce() one
inline fun <S, T: S> Array<out T>.reduce(operation: (acc: S, T) -> S): S {
if (isEmpty())
throw UnsupportedOperationException("Empty array can't be reduced.")
var accumulator: S = this[0]
for (index in 1..lastIndex) {
accumulator = operation(accumulator, this[index])
}
return accumulator
}
here the accumulator variable of type S assigned with first element from the array with type T.
Can't wrap my head around the real use case of reduce() function with two data types. Here synthetic example which actually doesn't make any sense.
open class A(var width: Int = 0)
class B(width: Int) : A(width)
val array = arrayOf(A(7), A(4), A(1), A(4), A(3))
val res = array.reduce { acc, s -> B(acc.width + s.width) }
Seems most real life use cases with this function use this signature:
inline fun <T> Array<out T>.reduce(operation: (acc: T, T) -> T): T
Can you help with providing some examples, where reduce() function can be useful with different types.
Here is an example:
interface Expr {
val value: Int
}
class Single(override val value: Int): Expr
class Sum(val a: Expr, val b: Expr): Expr {
override val value: Int
get() = a.value + b.value
}
fun main(args: Array<String>) {
val arr = arrayOf(Single(1), Single(2), Single(3));
val result = arr.reduce<Expr, Single> { a, b -> Sum(a, b) }
println(result.value)
}
I would like flow to determine the output type of applying a function composition. For example, I would like flow to deduce that type of o is { b: boolean }:
const foo = s => s.length;
const bar = n => n > 3;
const baz = b => ({ b });
// The list of functions
const funcs = [foo, bar, baz];
// This is equivalent to: baz(bar(foo('hello')))
const o = funcs.reduce((acc, func) => func(acc), 'hello');
console.log(o); // { b: true }
I tried this with flow 0.74:
// #flow
type Foo = string => number;
type Bar = number => boolean;
type Baz = boolean => {b: boolean};
const foo: Foo = (s: string): number => s.length;
const bar: Bar = (n: number): boolean => n > 3;
const baz: Baz = (b: boolean): {b: boolean} => ({ b });
// Ok, type is { b: boolean }, but I want to work with
// the array of functions `funcs`:
const a = baz(bar(foo('hello')));
console.log(a); // { b: true }
// We need Funcs type to be Tuple[Foo, Bar, Baz], not Array<Foo|Bar|Baz>
type Funcs = [Foo, Bar, Baz];
const funcs: Funcs = [foo, bar, baz];
// Ok, type is { b: boolean }, but array length is hardcoded:
const b = funcs[2](funcs[1](funcs[0]('hello')));
console.log(b); // { b: true }
// Got flow error:
// Cannot call func with acc bound to the first parameter because:
// • number [1] is incompatible with string [2].
// • number [1] is incompatible with boolean [3].
// • boolean [4] is incompatible with string [2].
// • boolean [4] is incompatible with number [5].
// • object type [6] is incompatible with string [2].
// • object type [6] is incompatible with number [5].
// • object type [6] is incompatible with boolean [3].
// • string [7] is incompatible with number [5].
// • string [7] is incompatible with boolean [3].
//
// [2][1] 3│ type Foo = string => number;
// [5][4] 4│ type Bar = number => boolean;
// [3][6] 5│ type Baz = boolean => {b: boolean};
// :
// 21│ const b = funcs[2](funcs[1](funcs[0]('hello')));
// 22│ console.log(b); // { b: true }
// 23│
// [7] 24│ const c = funcs.reduce((acc, func) => func(acc), 'hello');
// 25│ console.log(c);
// 26│
// 27│ //let x = 'hello';
const c = funcs.reduce((acc, func) => func(acc), 'hello');
console.log(c);
// Same error as above.
let d = 'hello';
for (let func of funcs) {
d = func(d);
}
console.log(d);
How could I get flow deduce the output type without hardcoding the array length?
I am trying to reverse a Map in Kotlin. So far, I have come up with:
mapOf("foo" to 42)
.toList()
.map { (k, v) -> v to k }
.toMap()
Is there any better way of doing this without using a middleman(middlelist)?
Since the Map consists of Entrys and it is not Iterable you can use Map#entries instead. It will be mapped to Map#entrySet to create a backed view of Set<Entry>, for example:
val reversed = map.entries.associateBy({ it.value }) { it.key }
OR use Iterable#associate, which will create additional Pairs.
val reversed = map.entries.associate{(k,v)-> v to k}
OR using Map#forEach:
val reversed = mutableMapOf<Int, String>().also {
// v-- use `forEach` here
map.forEach { (k, v) -> it.put(v, k) }
}.toMap()
// ^--- you can add `toMap()` to create an immutable Map.
Here is a simple extension function that reverse a map - without generating unneeded garbage (like pairs, intermediate data structures and unnecessary closures )
fun <K, V> Map<K, V>.reversed() = HashMap<V, K>().also { newMap ->
entries.forEach { newMap.put(it.value, it.key) }
}
note that apply is inlined, and entries.forEach is also inlined (which is not the same for Map::forEach)
In case your map is not a 1-1 mapping and you want the inversion to be a list of values:
mapOf(1 to "AAA", 2 to "BBB", 3 to "BBB").toList()
.groupBy { pair -> pair.second } // Pair<Int, String>
.mapValues { entry ->
entry.value.map { it.first } // Entry<String, List<Pair<Int, String>>
}
If you need to reverse a multimap like m: Map<K, List<V>> to a Map<V, List<K>> you can do
m
.flatMap { it.value.map { oneValue -> oneValue to it.key } }
.groupBy({ it.first }, { it.second })
.toMap()
In sequence,
mapOf('a' to listOf('b', 'c'), 'd' to listOf('b'))
gets flat mapped to a sequence like
listOf('b' to 'a', 'c' to 'a', 'b' to 'd') which gets grouped to
listOf('b' to listOf('a', 'd'), 'c' to listOf('a')) which then gets converted to a map.
This probably creates intermediate objects.
I'm still learning the ins and outs of Kotlin, but I had the same requirement and as of Kotlin 1.2 it appears that you can iterate over a Map and so map() it directly like this:
#Test
fun testThatReverseIsInverseOfMap() {
val intMap = mapOf(1 to "one", 2 to "two", 3 to "three")
val revMap = intMap.map{(k,v) -> v to k}.toMap()
assertTrue(intMap.keys.toTypedArray() contentEquals revMap.values.toTypedArray())
assertTrue(intMap.values.toTypedArray() contentEquals revMap.keys.toTypedArray())
}
This is my take on a 1:1 map
private fun <K, V> Map<K, V>.reverseOneToOneMap(): Map<V, K> {
val result = this.entries.associateBy({ it.value }) { it.key }
if (result.size != this.size) {
throw RuntimeException("Map must be 1:1")
}
return result
}
The following code uses a cache object outside of the factorial function. The factorial function itself is large which has too many concerns of finding factorial and caching.
How can I convert this code to a higher-order function and generate the same result when I call
console.log(factorial(5));
console.log(factorial(7));
cache = { }
function factorial(n) {
if (n === 0) {
return 1;
}
if (cache[n])
{
return cache[n];
}
console.log("Stack Up: " + n);
var value = n * factorial(n - 1);
console.log("Stack Down: " + value);
cache[n] = value;
return value;
}
console.log(factorial(5));
console.log(factorial(7));
There's already other answers out there for memoising recursive functions, but I'll adapt that answer to factorial in javascript so you can see how it works more easily
The secret to writing memoised recursive functions is continuation passing style. A similar technique works when you want to make a non-tail recursive function stack-safe.
I'll leave some console.log statements in this first example so you can see when it's actually computing and when it's just doing a memo lookup.
const memoise = f => {
const memo = new Map()
const compute = (x, k) =>
(console.log('compute', x),
memo.get(x, memo.set(x, f(x,k))))
const lookup = x =>
(console.log('lookup', x),
memo.has(x) ? memo.get(x) : compute(x, lookup))
return lookup
}
const factk = (x, k) => {
if (x === 0)
return 1
else
return x * k(x - 1)
}
const memfact = memoise(factk)
console.log(memfact(5)) // 120
console.log(memfact(7)) // 5040
Here I've removed the console.log calls inside of memoise and instead demonstrate a memoised fibonacci function vs an unmemoised one. Compare the dramatic time difference between memoise(fibk) and badfib
const memoise = f => {
const memo = new Map()
const compute = (x, k) =>
memo.get(x, memo.set(x, f(x,k)))
const lookup = x =>
memo.has(x) ? memo.get(x) : compute(x, lookup)
return lookup
}
const fibk = (x, k) => {
if (x < 2)
return x
else
return k(x - 1) + k(x - 2)
}
const badfib = x => {
if (x < 2)
return x
else
return badfib(x - 1) + badfib(x - 2)
}
console.time('memoised')
console.log(memoise (fibk) (35)) // 9227465 1.46ms
console.timeEnd('memoised')
console.time('unmemoised')
console.log(badfib(35)) // 9227465 135.85ms
console.timeEnd('unmemoised')
I have two type of value on handlebar page and needs to compare the first one from second.
I can print value of following code
{{articledetails.content_writer_id}}
before writing each loop on page. Now i want to compare the value like following. but i can not get the scope of articledetails.content_writer_id in below code.
{{#each contentwriterdetails}}
{{#compare this.id "==" articledetails.content_writer_id }}
I have already registered compare helper by using this code.
handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) {
var operators, result;
if (arguments.length < 3) {
throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
}
if (options === undefined) {
options = rvalue;
rvalue = operator;
operator = "===";
}
operators = {
'==': function (l, r) { return l == r; },
'===': function (l, r) { return l === r; },
'!=': function (l, r) { return l != r; },
'!==': function (l, r) { return l !== r; },
'<': function (l, r) { return l < r; },
'>': function (l, r) { return l > r; },
'<=': function (l, r) { return l <= r; },
'>=': function (l, r) { return l >= r; },
'typeof': function (l, r) { return typeof l == r; }
};
if (!operators[operator]) {
throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator);
}
result = operators[operator](lvalue, rvalue);
if (result) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
and above helper is working fine as i have checked that.
Any help would be appreciated.
Use the parent's context path:
{{#each contentwriterdetails}}
{{#compare this.id "==" ../articledetails.content_writer_id }}