admin管理员组

文章数量:1421432

I am trying to update a value in an array in a nested object structure using Ramda.

I want to update the value prop of the object in C with the name blah

const o = {
  A: {
    B: {
      C: [
        {name: 'blah', value: 'blah'},
        {name: 'vtha', value: 'blah'},
      ]
    }
  }
}

I've been plying with lenses, but it seems quite verbose and I figure I am doing it wrong.

Ideally, I would love something that returns a new object.

const res = fn(o)


{
  A: {
    B: {
      C: [
        {name: 'blah', value: 'vtha'}
        {name: 'vtha', value: 'blah'},
      ]
    }
  }
}

I am trying to update a value in an array in a nested object structure using Ramda.

I want to update the value prop of the object in C with the name blah

const o = {
  A: {
    B: {
      C: [
        {name: 'blah', value: 'blah'},
        {name: 'vtha', value: 'blah'},
      ]
    }
  }
}

I've been plying with lenses, but it seems quite verbose and I figure I am doing it wrong.

Ideally, I would love something that returns a new object.

const res = fn(o)


{
  A: {
    B: {
      C: [
        {name: 'blah', value: 'vtha'}
        {name: 'vtha', value: 'blah'},
      ]
    }
  }
}
Share Improve this question edited Aug 6, 2017 at 7:57 Toby Hede asked Aug 6, 2017 at 7:24 Toby HedeToby Hede 37.2k28 gold badges137 silver badges164 bronze badges 4
  • 2 That's why proper types are more important than proper algorithms: you chose the weird structure, no wondering to modify it you need weird code. – zerkms Commented Aug 6, 2017 at 7:27
  • It's data being returned from an api call. I can split this into sub elements and stitch it back together, but surely updating a value inside a structure is something that can be done in a reasonable way? – Toby Hede Commented Aug 6, 2017 at 7:40
  • Yep, do it in imperative way: const obj = o.A.B.C.find(nested => nested.name === 'blah'); if (obj !== undefined) { obj.value = 'vtha'; } it's easy to read and maintain. If necessary - wrap it in a function to look "functional". – zerkms Commented Aug 6, 2017 at 7:43
  • 1 @zerkms That's why proper types are more important than proper algorithms. Indeed and additionally: Proper types naturally lead to proper algorithms. We need to talk more about types in Javascript. – user6445533 Commented Aug 6, 2017 at 14:13
Add a ment  | 

3 Answers 3

Reset to default 4

If you want to do it in immutable way it would be like

const fn = over(
  R.lensPath(['A', 'B', 'C']),
  R.map(
    o => o.name === 'blah' ? R.assoc('value', 'vtha', o): o
  )
)

Demo.

If you want to avoid manually defining functions by all means you could replace mapped function with

R.ifElse(
  R.propEq('name', 'blah'),
  R.assoc('value', 'blah'),
  R.identity
)

But imho ternary operator looks more readable here.

You could try using filter and where, i wrote an example below.

const o = {
  A: {
    B: {
      C: [
        {name: 'blah', value: 'blah'},
        {name: 'vtha', value: 'blah'},
      ]
    }
  }
};

var pred = R.filter(R.where({name: R.contains('blah')}));

pred(o.A.B.C);

To update the array in the object we need the path to the array. Then we can update the result with a lens and a helper function adjustIfSatisfies

const { propEq, identity, over, assoc, curry, lensPath, map, ifElse } = R
const o = {
  A: {
    B: {
      C: [
        {name: 'blah', value: 'blah'},
        {name: 'vtha', value: 'blah'},
      ]
    }
  }
}

const adjustIfSatisfies = curry(
  (pred, updateFn, samples) => {
    return map(ifElse(pred, updateFn, identity), samples)
  }
)

const result = over(
  lensPath(['A', 'B', 'C']), 
  adjustIfSatisfies(
    propEq('name', 'blah'), 
    assoc('value', 'vtha')
  ),
  o
)

console.log(result)
<script src="https://cdnjs.cloudflare./ajax/libs/ramda/0.27.1/ramda.min.js"></script>

本文标签: javascriptUpdate nested values based on a condition using RamdaStack Overflow