以功能方式解析结构化数据(例如,不变异)

时间:2022-11-18 22:01:50

Imagine you have the following data in a file:

想象一下,文件中包含以下数据:

Group1
  Thing1
  Thing2
Group2
  Thing1
  Thing2
  Thing3
Group3
Group4
  Thing1

It's easy to write a "parser" which loops through the file line-by-line, remembering the current Group (in a variable) and then writing all the Things to an object, neatly grouped by their respective group:

编写一个“解析器”很容易,它逐行循环遍历文件,记住当前组(在一个变量中),然后将所有的东西写入一个对象,整齐地按其各自的组分组:

// Very naive implementation for illustrative purposes only
let groups = {}
let currentGroup = null
data
  .split(/\n/)
  .forEach(entry => {
    const matches = entry.match(/^(Group\d+)$/)
    if (matches) {
      currentGroup = matches[1]
      groups[currentGroup] = []
    } else {
      groups[currentGroup].push(entry.trim())
    }
  })

which gives me:

这给了我:

{
  Group1: [
    'Thing1', 'Thing2'
  ],
  Group2: [
    'Thing1', 'Thing2', 'Thing3'
  ],
  ...
}

What's the best way to achieve this without mutating groups and currentGroup, in a purely functional way? Do I need to take a harder look at Array.reduce, because I've seen some (IMHO rather mind-boggling) use-cases to transform an Array into an Object, or is that not going to help here?

在没有以纯函数方式改变组和currentGroup的情况下实现这一目标的最佳方法是什么?我是否需要更加努力地看看Array.reduce,因为我已经看到一些(恕我直言,相当令人难以置信)的用例将一个数组转换为一个对象,或者这对我们没有帮助?

1 个解决方案

#1


2  

Yes, you'd want to use reduce here:

是的,你想在这里使用reduce:

data
.split(/\n/)
.reduce(({groups, currentGroup}, entry) => {
  const matches = entry.match(/^(Group\d+)$/)
  if (matches) {
    groups[matches[1]] = []
    return {currentGroup: matches[1], groups};
  } else {
    groups[currentGroup] = groups[currentGroup].concat([entry.trim()]);
    return {currentGroup, groups};
  }
}, {groups: {}, currentGroup: null})
.groups

However, there is no reasonable way in JS to create a map object without mutation. As long as you keep your property assignments local, there's nothing wrong with that.

但是,JS没有合理的方法来创建没有变异的地图对象。只要您将财产分配保持在本地,就没有任何问题。

#1


2  

Yes, you'd want to use reduce here:

是的,你想在这里使用reduce:

data
.split(/\n/)
.reduce(({groups, currentGroup}, entry) => {
  const matches = entry.match(/^(Group\d+)$/)
  if (matches) {
    groups[matches[1]] = []
    return {currentGroup: matches[1], groups};
  } else {
    groups[currentGroup] = groups[currentGroup].concat([entry.trim()]);
    return {currentGroup, groups};
  }
}, {groups: {}, currentGroup: null})
.groups

However, there is no reasonable way in JS to create a map object without mutation. As long as you keep your property assignments local, there's nothing wrong with that.

但是,JS没有合理的方法来创建没有变异的地图对象。只要您将财产分配保持在本地,就没有任何问题。