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

Create keyed Maps from nested Lists with Immutable.js

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

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

我想要得到的是一个包含其他 Map 的 Map,包含的 Map 的键是对象的值(再次请参阅此 post 末尾的示意图)。

我让它在第一层工作:

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

使用 "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());

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

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/

到目前为止,这一直运行良好,而且编码相当硬。如果有人对此有更优雅的解决方案,我很高兴了解它!

至于生成性更强的解决方案,我将之前的答案重写为递归方法:

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/

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