1

In a ramda pipe, I want to subtract the values of two array keys, to ultimately end up with an array of those differences.

For example, consider the following mice_weights array. I want to get an array with the differences weight_post minus weight_pre, for the male mice only.

const mice_weights = [
    {
        "id": "a",
        "weight_pre": 20,
        "weight_post": 12,
        "is_male": true
    },
    {
        "id": "b",
        "weight_pre": 25,
        "weight_post": 19,
        "is_male": false
    },
    {
        "id": "c",
        "weight_pre": 15,
        "weight_post": 10,
        "is_male": true
    },
    {
        "id": "d",
        "weight_pre": 30,
        "weight_post": 21,
        "is_male": false
    }
]

So based on this answer, I can construct 2 equivalent pipes, get_pre() and get_post():

const R = require("ramda");

filter_males = R.filter(R.path(["is_male"])) // my filtering function

const get_pre = R.pipe(
    filter_males,
    R.map(R.prop("weight_pre"))
)

const get_post = R.pipe(
    filter_males,
    R.map(R.prop("weight_post"))
)

res_pre  = get_pre(mice_weights) // [20, 15]
res_post = get_post(mice_weights) // [12, 10]


const res_diff = res_pre.map((item, index) => item - res_post[index]) // taken from: https://stackoverflow.com/a/45342187/6105259

console.log(res_diff); // [8, 5]

Although [8, 5] is the expected output, I wonder if there's a shorter way using ramda's pipe such as:

// pseudo-code

const get_diff = R.pipe(
    filter_males,
    R.subtract("weight_pre", "weight_post")
)

get_diff(mice_weights) // gives [8, 5]

Is it possible to achieve something similar using ramda? Perhaps there's a built-in functionality for such a task?

Emman
  • 3,695
  • 2
  • 20
  • 44

3 Answers3

3

To get a the weight diff in a single object, create a function using R.pipe that takes the relevant props values with R.props, and applies them to R.subtract.

Now you can create a functions that filters the items, and maps the objects using weight calculation function:

const { pipe, props, apply, subtract, filter, prop, map,  } = R

const calcWeightDiff = pipe(
  props(['weight_pre', 'weight_post']), 
  apply(subtract)
)

const fn = pipe(
  filter(prop('is_male')),
  map(calcWeightDiff)
)

const mice_weights = [{"id":"a","weight_pre":20,"weight_post":12,"is_male":true},{"id":"b","weight_pre":25,"weight_post":19,"is_male":false},{"id":"c","weight_pre":15,"weight_post":10,"is_male":true},{"id":"d","weight_pre":30,"weight_post":21,"is_male":false}]

const result = fn(mice_weights)

console.log(result) // gives [8, 5]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
1

Sorry, I don't know about ramda pipes, but this is a trivial matter for array filtering and mapping.

const get_diff = (n, v) => // this takes a field and value to filter
       mice_weights 
       .filter(f => f[n] === v) // this keeps only datasets that have the field/value combo you're seeking
       .map(f => f.weight_pre - f.weight_post) // this gets the diff

const mice_weights = [{
    "id": "a",
    "weight_pre": 20,
    "weight_post": 12,
    "is_male": true
  },
  {
    "id": "b",
    "weight_pre": 25,
    "weight_post": 19,
    "is_male": false
  },
  {
    "id": "c",
    "weight_pre": 15,
    "weight_post": 10,
    "is_male": true
  },
  {
    "id": "d",
    "weight_pre": 30,
    "weight_post": 21,
    "is_male": false
  }
]

const get_diff = (n, v) => mice_weights.filter(f => f[n] === v).map(f => f.weight_pre - f.weight_post)

console.log(get_diff('is_male', true)) // gives [8, 5]
Kinglish
  • 23,358
  • 3
  • 22
  • 43
1

I would propose to use props and reduceRight functions in order to achieve that:

const getProps = R.props(['weight_pre', 'weight_post'])

const subtract = R.reduceRight(R.subtract)(0)

const get_diff = R.pipe(
    R.filter(R.path(['is_male'])),
    R.map(R.pipe(getProps, subtract))
)

console.log(get_diff(mice_weights));
  • Thank you! Could you please explain a bit about `R.reduceRight(R.subtract)(0)` ? For example, about the role of `(0)` and how it works. – Emman Feb 02 '22 at 20:55
  • `reduce`/`reduceRight` have to do with arbitrary-length lists. Using them for a fixed-length tuple seems like the wrong tool for the job. `apply(subtract)` seems cleaner. – Scott Sauyet Feb 03 '22 at 01:32
  • 1
    @ScottSauyet, thank you for pointing this out! – Konstantin Samarin Feb 03 '22 at 07:42