【问题标题】:Decrease "position" property with Ramda使用 Ramda 减少“位置”属性
【发布时间】:2019-06-15 19:04:42
【问题描述】:

有了这个对象:

const state = {
  a: {position: 1},
  b: {position: 2},
  c: {position: 3},
  d: {position: 4},
  e: {position: 5},
}

我想删除 b 对象,然后将 position 从具有较高位置的对象中减少 1(所以只是到 cde)。结果状态应该是:

{
  a: {position: 1},
  c: {position: 2},
  d: {position: 3},
  e: {position: 4},
}

在玩了 Ramda 之后,我得到了这样的结果:

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

它有效,但我对它并不完全满意,因为我觉得它有点冗长。你觉得有更好的写法吗?

【问题讨论】:

  • 你应该使用Map,而不是位置可以通过插入顺序隐式编码

标签: javascript functional-programming ramda.js


【解决方案1】:

只需过滤和更新。然后删除。

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

【讨论】:

  • 我对这个解决方案投了反对票,因为它篡改了原始对象而不是创建一个新对象。
  • 是的,但我认为这并不一定意味着您必须将其从原始对象中删除。正如您在 OP 初始尝试中看到的那样,clone 的使用表明 OP 不想篡改原始对象。
【解决方案2】:

一个使用lenses的ramda解决方案:

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)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

【讨论】:

    【解决方案3】:

    我会稍微拆分一下:

    首先是一个函数,它返回一个检查{position} 对象的position 属性是否低于给定数字的函数:

    const positionLowerThan = (num) => propSatisfies(lt(num), 'position');
    

    其次,一个函数将采用 {position} 对象并简单地减少其 position 属性:

    const decreasePosition = over(lensProp('position'), dec);
    

    把所有东西放在一起:

    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},
      })
    
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

    【讨论】:

      【解决方案4】:

      我可能会这样做:

      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'))
      <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

      请注意,Nina 和 customcommander 之间关于 remove 的讨论与此处相关。此版本不会更改您的原始版本。 Ramda 强调永远不要这样做。

      如果您的状态值不仅仅是{position: ?},那么这个版本应该可以解决问题:

      const reshape = (state, key, pos = state[key].position) => dissoc(key, map(
        ({position, ...rest}) => position > pos 
          ? {position: position - 1, ...rest} 
          : {position, ...rest},
        state
      ))
      

      或者,正如 Emi 指出的那样,这个版本可能会更高效:

      const reshape = (state, key, pos = state[key].position) => dissoc(key, map(
        (obj) => obj.position > pos ? {...obj, position: obj.position - 1} : obj,
        state
      ))
      

      【讨论】:

      • 返回相同的对象引用不会比使用 {position, ...rest} 传播它更高效吗?喜欢: (obj) => obj.position > pos ? {...obj,位置:位置 - 1}:obj
      猜你喜欢
      • 1970-01-01
      • 2022-01-24
      • 2013-04-23
      • 1970-01-01
      • 2022-01-25
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多