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?

3 Answers 3

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>

Sign up to request clarification or add additional context in comments.

Comments

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]

1 Comment

This is a cool solution and eye-opening. Thanks!
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));

3 Comments

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.
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.
@ScottSauyet, thank you for pointing this out!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.