1

現在のプロジェクトでは、次のような形式のデータを返す API を使用しています。

{
  groups: [
    {
      items: [
        {
          points: [
            { name: "name1", ... },
            { name: "name2", ... },
            { name: "name3", ... },
            ...
          ],
          ...
        },
        ...
      ]
    },
    ...
  ],
  ...
};

上記の形式のオブジェクトと、それぞれを にマッピングするオブジェクトを取り、同じ構造を返しますが、それぞれに対応する を含む純粋な関数を作成したいと思います。mapValuesnamevaluepointvaluename

たとえば、呼び出すと次のようにmapValues(data, { name1: "value1", name2: "value2", name3: "value3" })返されます。

{
  groups: [
    {
      items: [
        {
          points: [
            { name: "name1", value: "value1", ... },
            { name: "name2", value: "value2", ... },
            { name: "name3", value: "value3", ... },
            ...
          ],
          ...
        },
        ...
      ]
    },
    ...
  ],
  ...
};

これが私の最初のパスです:

function mapValues(data, values) {
  return _.extend({}, data, {
    groups: _.map(ui.groups, (group) => {
      return _.extend({}, group, {
        items: _.map(group.items, (item) => {
          return _.extend({}, item, {
            points: _.map(item.points, (point) => {
              return _.extend({ value: values[point.name] }, point);
            })
          });
        })
      });
    })
  });
}

これは機能しますが、重複するコードをかなり入れ子にしています。2 回目の試行では、再帰に到達しました。

function mapValues(data, values) {
  return (function recursiveMap(object, attributes) {
    if (attributes.length === 0) { return _.extend({ value: values[object.name] }, object); }
    let key = attributes[0];
    return _.extend({}, object, {
      [key]: _.map(object[key], child => recursiveMap(child, attributes.slice(1)))
    });
  })(ui, ["groups", "items", "points"]);
}

これも機能しますが、読みにくく、あまり簡潔ではありません。

Lodash を使用してオブジェクトを再帰的にマップするよりクリーンな方法はありますか? 理想的には、機能的なアプローチを探しています。

4

2 に答える 2

1

Object.assignこれは、派手な関数を使用せずに実行できる方法です

var data = <your data here>;
var values = <your mapped values>;

data.groups.items.points.map(p=>
  Object.assign(p, {value: values[p.name]})
);

これが機能するのは、配列とオブジェクトが参照渡しであるためです。したがって、値を変更すると、元の値が変更されます。

元のデータセットを変更したくない場合は{}、最初の引数として使用して (新しい空のオブジェクトに割り当てるため)、各オブジェクトの明確な読み取り/書き込みパスを示す必要があります。

var newData = Object.assign({}, data,
  {groups:
    {items:
      {points: data.groups.items.points.map(p=>
        Object.assign({}, p, {value: values[p.name]})
      )}
    }
  }
);
于 2016-05-10T14:20:54.183 に答える
0

あなたがLodashを欲しがっていたことは知っていますが、私はしばらく前に同じ問題を抱えていました.nervghによって作成された優れたツールを使用しています. とてもシンプルですが便利です。を使用してこの関数を純粋に調整しObject.assign、キーパラメーターを受け入れて、必要に応じて微調整できます。あなたはアイデアを得る。

function mapValues(data, values) {
  var iterator = new RecursiveIterator(data);
  for(let {node} of iterator) {
    if(node.hasOwnProperty('name')) {
        node.value = values[node.name];
    }
  }
  return data;
}
于 2016-05-10T05:57:03.350 に答える