使用Immutable.js从嵌套列表创建键控映射

时间:2017-08-05 17:42:34

标签: immutable.js

我正在使用无法在服务器端修改的数据集。因此,我尝试在客户端上设置本地数据模型,以便在更新部分数据时可以轻松遍历模型。

因此,我正在尝试从包含列表的多层次地图创建多层次地图,这些地图本身包含地图等(请参阅本文末尾的示意图)。

我想要的是一个包含其他地图的地图,其中包含的地图的关键字是对象的价值(再次请参阅本文末尾的原理图)。

我让它在第一级工作:

const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));

在此处查看此行动:https://jsfiddle.net/9f0djcb0/4/

但是最多有3个级别的嵌套数据,我无法理解如何完成转换。任何帮助表示赞赏!

原理图数据集:

// This is what I got
const dataset = [
  {
    field: 'lorem',
    value: 'ipsum',
    more: [
      {
        field: 'lorem_lvl1',
        value: 'ispum_lvl1',
        more: [
          {
            field: 'lorem_lvl2',
            value: 'ispum_lvl2',
            more: [
              {
                field: 'lorem_lvl3',
                value: 'ispum_lvl3',
              }
            ]
          }
        ]
        }
    ]
  },
  {
  field: 'glorem',
  value: 'blipsum'
  },
  {
  field: 'halorem',
  value: 'halipsum'
  }
];

这是我想去的地方:

// This is what I want
const dataset_wanted = {
  ipsum: {
    field: 'lorem',
    value: 'ipsum',
    more: {
      lorem_lvl1: {
        field: 'lorem_lvl1',
        value: 'ispum_lvl1',
        more: {
          lorem_lvl2: {
            field: 'lorem_lvl2',
            value: 'ispum_lvl2',
            more: {
              lorem_lvl3: {
                field: 'lorem_lvl3',
                value: 'ispum_lvl3',
              }
            }
          }
        }
        }
    }
  },
  glorem: {
    field: 'glorem',
    value: 'blipsum'
  },
  halorem: {
    field: 'halorem',
    value: 'halipsum'
  }
};

3 个答案:

答案 0 :(得分:0)

使用“getIn”检索嵌套结构是更好的。

const data = Immutable.fromJS(dataset[0]);
const firstLevel = data.getIn(['more']);
const twoLevel = firstLevel.getIn([0,'more']);
const threeLevel = twoLevel.getIn([0,'more']);
console.log(firstLevel.toJS(),twoLevel.toJS(),threeLevel.toJS());

答案 1 :(得分:0)

经过一段时间后,我想出了一个适合我的解决方案:

let sec, third, objThird;

// 1st level: simple mapping
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));

// 2nd level: walk through updated firstLevel's subobjects and do the mapping again:
const secondLevel = firstLevel.map((obj) => {
  if (obj.has('more')) {
    sec = obj.get('more').toMap().mapKeys((key, value) => value.get('value'));

    // 3nd level: walk through updated secondLevel's subobjects and do the mapping again:
    objThird = sec.map((o) => {
      if (o.has('more')) {
        third = o.get('more').toMap().mapKeys((key, value) => value.get('value'));
        o = o.set('more', third);
      }
      return o;
    });
    obj = obj.set('more', objThird);
  }
  return obj;
});

在此处查看此行动:https://jsfiddle.net/9f0djcb0/7/

到目前为止,这一直很好用,很难编码。如果有人对此有更优雅的解决方案,我很高兴了解它!

答案 2 :(得分:0)

至于更具生成性的解决方案,我之前重新编写了一个递归方法的答案:

function mapDeep(firstLevel) {
  return firstLevel.map((obj) => {
    if (obj.has('more')) {
      const sec = obj.get('more').toMap().mapKeys((key, value) => value.get('value'));
      const objNext = mapDeep(sec);
      obj = obj.set('more', objNext);
    }
    return obj;
  });
}

第一级仍需要手动映射。

const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
const secondLevel = mapDeep(firstLevel);

再一次,看看它的实际效果:https://jsfiddle.net/9f0djcb0/12/

这对我来说已经足够了。仍然觉得这可以更聪明地解决(和更高性能)..干杯:)