1
votes

Diminuer la propriété «position» avec Ramda

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?


1 commentaires

Vous devriez utiliser Map à la place où la position pourrait être implicitement codée par ordre d'insertion


4 Réponses :


0
votes

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);


2 commentaires

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.



0
votes

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)


0 commentaires

0
votes

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');


0 commentaires

3
votes

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'))


1 commentaires

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