使用 lodash 展平对象内嵌套数组的功能方法?

Functional way to flatten nested array inside an object using lodash?

我有这个facebookResponseObject,我想展平数组类型的值

现在我正在使用这样的 reduce 函数,但我想知道是否有更简洁的功能方法来解决这个问题...

输入样本

const facebookResponseObject = {
  account_currency: "xxx",
  campaign_name: "xxxxxxxx",
  account_name: "xxxxxxxx",
  adset_name: "xxxxxxxx",
  ad_name: "xxxxxxxx",
  reach: "xxxx",
  impressions: "xxxx",
  frequency: "xxxx",
  spend: "xxxx",
  cpm: "xxxx",
  inline_link_clicks: "xxxx",
  cost_per_inline_link_click: "xxxx",
  inline_link_click_ctr: "xxxx",
  clicks: "xxxx",
  cost_per_unique_click: "xxxx",
  cost_per_action_type: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  actions: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "post_reaction", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "post", value: "xxxx" },
    { action_type: "comment", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  test_key: [
    { action_type: "test1", value: "xxxx" },
    { action_type: "test2", value: "xxxx" },
    { action_type: "test3", value: "xxxx" },
    { action_type: "test4", value: "xxxx" },
  ],
  cpc: "xxxx",
  ctr: "xxxx",
  date_start: "xxxx-xx-xx",
  date_stop: "xxxx-xx-xx",
  account_id: "xxxxxxxx",
};

变换函数

const formatResponse = _.reduce(
  facebookResponseObject,
  (acc, cur, key) => {
    if (_.isArray(cur)) {
      acc = {
        ...acc,
        ..._.chain(cur)
          .keyBy(obj => `${key}.${obj.action_type}`)
          .mapValues(v => v.value)
          .value(),
      };
    } else {
      acc[key] = cur;
    }
    return acc;
  },
  {},
);

输出

{
  account_currency: 'xxx',
  campaign_name: 'xxxxxxxx',
  account_name: 'xxxxxxxx',
  adset_name: 'xxxxxxxx',
  ad_name: 'xxxxxxxx',
  reach: 'xxxx',
  impressions: 'xxxx',
  frequency: 'xxxx',
  spend: 'xxxx',
  cpm: 'xxxx',
  inline_link_clicks: 'xxxx',
  cost_per_inline_link_click: 'xxxx',
  inline_link_click_ctr: 'xxxx',
  clicks: 'xxxx',
  cost_per_unique_click: 'xxxx',
  'cost_per_action_type.link_click': 'xxxx',
  'cost_per_action_type.landing_page_view': 'xxxx',
  'cost_per_action_type.post_engagement': 'xxxx',
  'cost_per_action_type.page_engagement': 'xxxx',
  'cost_per_action_type.lead': 'xxxx',
  'cost_per_action_type.video_view': 'xxxx',
  'cost_per_action_type.like': 'xxxx',
  'actions.link_click': 'xxxx',
  'actions.landing_page_view': 'xxxx',
  'actions.post_engagement': 'xxxx',
  'actions.page_engagement': 'xxxx',
  'actions.post_reaction': 'xxxx',
  'actions.lead': 'xxxx',
  'actions.post': 'xxxx',
  'actions.comment': 'xxxx',
  'actions.video_view': 'xxxx',
  'actions.like': 'xxxx',
  'test_key.test1': 'xxxx',
  'test_key.test2': 'xxxx',
  'test_key.test3': 'xxxx',
  'test_key.test4': 'xxxx',
  cpc: 'xxxx',
  ctr: 'xxxx',
  date_start: 'xxxx-xx-xx',
  date_stop: 'xxxx-xx-xx',
  account_id: 'xxxxxxxx'
}

您可以使用 flatMap 来迭代对象的条目。

  • 不要触摸具有非数组值的条目
  • 当有数组值时,将其元素迭代为return个新的键值对
    • 作为密钥,将原始密钥与 action_type
    • 作为一个值,取 value 属性
  • 因为我们使用的是 flatMap,所以我们确保不会 return 嵌套列表。
  • 使用Object.fromEntries变回对象

const flatEntries = (obj) => Object
  .entries(obj)
  .flatMap(
    ([ k, v ]) => Array.isArray(v)
      ? v.map(a => [ `${k}.${a.action_type}`, a.value ] )
      : [[k, v]]
  );

const flattenObject = obj => Object.fromEntries(flatEntries(obj));
  
console.log(flattenObject(facebookResponseObject()));


function facebookResponseObject() { return {
  account_currency: "xxx",
  campaign_name: "xxxxxxxx",
  account_name: "xxxxxxxx",
  adset_name: "xxxxxxxx",
  ad_name: "xxxxxxxx",
  reach: "xxxx",
  impressions: "xxxx",
  frequency: "xxxx",
  spend: "xxxx",
  cpm: "xxxx",
  inline_link_clicks: "xxxx",
  cost_per_inline_link_click: "xxxx",
  inline_link_click_ctr: "xxxx",
  clicks: "xxxx",
  cost_per_unique_click: "xxxx",
  cost_per_action_type: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  actions: [
    { action_type: "link_click", value: "xxxx" },
    { action_type: "landing_page_view", value: "xxxx" },
    { action_type: "post_engagement", value: "xxxx" },
    { action_type: "page_engagement", value: "xxxx" },
    { action_type: "post_reaction", value: "xxxx" },
    { action_type: "lead", value: "xxxx" },
    { action_type: "post", value: "xxxx" },
    { action_type: "comment", value: "xxxx" },
    { action_type: "video_view", value: "xxxx" },
    { action_type: "like", value: "xxxx" },
  ],
  test_key: [
    { action_type: "test1", value: "xxxx" },
    { action_type: "test2", value: "xxxx" },
    { action_type: "test3", value: "xxxx" },
    { action_type: "test4", value: "xxxx" },
  ],
  cpc: "xxxx",
  ctr: "xxxx",
  date_start: "xxxx-xx-xx",
  date_stop: "xxxx-xx-xx",
  account_id: "xxxxxxxx",
}; }

感谢您的帮助 @user3297291,我将对您的回答使用稍作修改的版本(使用 lodash)

const formatResponse = obj =>
  _.chain(obj)
    .toPairs()
    .flatMap(([key, value]) =>
      _.isArray(value)
        ? _.map(value, actionObj => [`${key}.${actionObj.action_type}`, actionObj.value])
        : [[key, value]],
    )
    .fromPairs()
    .value();