These are chat archives for ramda/ramda

25th
Jul 2018
Kurt Milam
@kurtmilam
Jul 25 2018 16:13
I am super stumped on a problem that involves reducing an array of arrays: https://goo.gl/HynyYQ
Hoping someone can help me with the magic part :D
const maxValue = 9

const rowTotal = reduce(add, 0)
const grandTotal = o(rowTotal, map(rowTotal))

// need some magic here that lets me double each array element
// as long as the sum of all array elements <= maxValue
const doubleRow = reduce(
  (acc, x) => append(multiply(2, x), acc),
  []
)
const doubleAllRows = reduce(
  (acc, x) => append(doubleRow(x), acc),
  []
)

const input = [
  [1, 1],
  [1, 1, 1],
  [1]
]
console.log(grandTotal(input)) // 6

const desiredOutput = [
  [2, 2],
  [2, 1, 1],
  [1]
]
console.log(grandTotal(desiredOutput)) // 9 (i.e. maxValue)

const actualOutput = doubleAllRows(input)
/*
[
  [2, 2],
  [2, 2, 2],
  [2]
]
*/

console.log(grandTotal(actualOutput)) // 12
perkee
@perkee
Jul 25 2018 17:11
okay this looks like it might be a job for mapAccum
we need to map over every value in the structure and we need to keep track of an accumulated total, so that's what springs to mind
Kurt Milam
@kurtmilam
Jul 25 2018 17:13
that sounds promising - I will take a look.
Mike Lambert
@lax4mike
Jul 25 2018 17:14
can you just use R.when?
const doubleRow = R.when(
  (arr) => R.sum(arr) < 10,
  R.reduce(
    (acc, x) => R.append(R.multiply(2, x), acc),
    []
  )
);
Kurt Milam
@kurtmilam
Jul 25 2018 17:21
@lax4mike I don't think that will do the trick, since doubleRow isn't aware of the grandTotal.
perkee
@perkee
Jul 25 2018 17:23
so here's a dumb example that ignores the nested nature of it but gets the ball rolling: https://codepen.io/perkee/pen/yqXmEo

inline:

const { sum, ifElse, mapAccum } = R;
const maximum = 40;
const fn = (acc, value) => {
    const double = 2 * value;
    const doubleAcc = double + acc;
    if (doubleAcc < maximum) {
        return [ doubleAcc, double ]
    }
    return [ value + acc, value ];
}

const arr = [ 3, 8, 3, 1, 2, 3, 1, 1 , 1 ];
console.log(JSON.stringify(mapAccum(fn, 0, arr)))
// result is [41,[6,16,6,2,4,3,2,1,1]], so first element is running total, second is this row transformed

The real trick is how to pass the running total into the mapAccum on the next row

I leave it to you to turn fn into something rad and pointfree
Kurt Milam
@kurtmilam
Jul 25 2018 17:27
This seems to do the trick but is a bit of a mind-bender: https://goo.gl/7tyUvs
Mike Lambert
@lax4mike
Jul 25 2018 17:27
hmm, how would that work in the situation that doubling a row will make the grand total over, but not doubling that row will make the grand total under?
Kurt Milam
@kurtmilam
Jul 25 2018 17:27
<= is fine.
I have a max value. Any result that is less than or equal to that max value is acceptable.
Mike Lambert
@lax4mike
Jul 25 2018 17:28
after you double them (or not)
perkee
@perkee
Jul 25 2018 17:28
you stop doubling on the element in the row where it puts the total over, not on the row where doubling would put you over
at least that's what I got from the example :shrug:
Kurt Milam
@kurtmilam
Jul 25 2018 17:29
See the (apparently working) example I linked above. (linking again here https://goo.gl/QZ9HT8 ).
@perkee that's correct.
Works for all max values from 6 (the input's grand total) through 12 (the grand total if all array elements are doubled), so it appears to do the trick.
@perkee thanks for mentioning mapAccum and for your example!
perkee
@perkee
Jul 25 2018 17:45
np! and good luck friend!