Avec cet objet:
const removeElement = (state, elementId) => { const newState = dissoc('b', state) return pipe( filter((currentDoc) => currentDoc.position > state[elementId].position), clone, forEachObjIndexed((value, key) => (value.position-=1), __), merge(newState) )(newState) } removeElement(state, 'b')
Je voudrais supprimer l'objet b
puis diminuer la position
de 1 des objets avec une position plus élevée (donc juste pour c
, d
et e
). L'état résultant devrait être:
{ a: {position: 1}, c: {position: 2}, d: {position: 3}, e: {position: 4}, }
Après m'être amusé avec Ramda, je me suis retrouvé avec quelque chose comme ceci:
const state = { a: {position: 1}, b: {position: 2}, c: {position: 3}, d: {position: 4}, e: {position: 5}, }
Cela fonctionne, mais je ne suis pas complètement satisfait car je le trouve un peu bavard. Pensez-vous qu'il existe une meilleure façon de l'écrire?
4 Réponses :
Il suffit de filtrer et de mettre à jour. Puis supprimez.
const state = { b: { position: 2 }, c: { position: 3 }, d: { position: 4 }, e: { position: 5 }, a: { position: 1 } }; Object .values(state) .filter(o => o.position > state.b.position) .forEach(o => o.position--); delete state.b; console.log(state);
J'ai décliné cette solution car elle altère l'objet d'origine plutôt que d'en créer un nouveau.
C'est vrai, mais je suppose que cela ne signifie pas nécessairement que vous devez le supprimer de l'objet d'origine. Comme vous pouvez le voir dans la tentative initiale de l'OP, l'utilisation de clone
suggère que l'OP ne voulait pas altérer l'objet d'origine.
Une solution ramda qui utilise des lentilles :
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
const { pipe, dissoc, lensProp, map, over, dec, gt, view, when, flip, prop } = R const pLens = lensProp('position'); const removeElement = (state, elementId) => pipe( dissoc(elementId), map(when( pipe( view(pLens), flip(gt)(view(pLens, prop(elementId, state)) )), over(pLens, dec) )) )(state) const state = {"a":{"position":1},"b":{"position":2},"c":{"position":3},"d":{"position":4},"e":{"position":5}} const result = removeElement(state, 'b') console.log(result)
Je diviserais un peu les choses:
Premièrement, une fonction qui renvoie une fonction qui vérifie si un objet {position}
a une propriété position
inférieure à celle donnée number:
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
Deuxièmement, une fonction qui prendra un objet {position}
et diminuera simplement sa propriété position
:
const {propSatisfies, over, lensProp, dec, pipe, omit, map, when, lt} = R; const positionLowerThan = (num) => propSatisfies(lt(num), 'position'); const decreasePosition = over(lensProp('position'), dec); const execute = (key, obj) => pipe(omit([key]), map(when(positionLowerThan(obj[key].position), decreasePosition))) (obj); console.log( execute('b', { a: {position: 1}, b: {position: 2}, c: {position: 3}, d: {position: 4}, e: {position: 5}, }) );
Tout assembler:
const decreasePosition = over(lensProp('position'), dec);
const positionLowerThan = (num) => propSatisfies(lt(num), 'position');
Je ferais probablement quelque chose comme ceci:
const reshape = (state, key, pos = state[key].position) => dissoc(key, map( (obj) => obj.position > pos ? {...obj, position: obj.position - 1} : obj, state ))
const reshape = (state, key, pos = state[key].position) => dissoc(key, map( ({position, ...rest}) => position > pos ? {position: position - 1, ...rest} : {position, ...rest}, state ))
Notez que la discussion entre Nina et customcommander concernant remove est pertinente ici. Cette version ne modifie pas votre original. Ramda se fait un devoir de ne jamais le faire.
Si vos valeurs d'état sont plus que simplement {position:?}
, alors cette version devrait faire l'affaire:
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Ou, comme le souligne Emi, cette version est susceptible d'être plus performante:
const {dissoc, map} = R const reshape = (state, key, pos = state[key].position) => dissoc(key, map( ({position}) => position > pos ? {position: position - 1} : {position}, state )) const state = { a: { position: 1 }, b: { position: 2 }, c: { position: 3 }, d: { position: 4 }, e: { position: 5 }, }; console.log(reshape(state, 'b'))
Ne serait-il pas plus performant de renvoyer la même référence d'objet que de l'étaler avec {position, ... repos}? Comme: (obj) => obj.position> pos? {... obj, position: position - 1}: obj
Vous devriez utiliser
Map
à la place où la position pourrait être implicitement codée par ordre d'insertion