Рекурсивная функция, которая выравнивает объект в массиве объектов - PullRequest
2 голосов
/ 29 октября 2019

Итак, у меня есть массив объектов, которые я получаю так:

[
  {
    accountName: {
      type: 'link',
      value: {
        value: '1234567890123456789',
        to: '/q?Id=1237896540789654',
      },
    },
    bank: {
      type: 'text',
      value: 'Foo Bank',
    },
  },
  {
    accountName: {
      type: 'link',
      value: {
        value: '9234567890123456789',
        to: '/q?Id=9234567890123456789',
      },
    },
    bank: {
      type: 'text',
      value: 'Foo Bank',
    },
  },
];

И мне нужен вывод, подобный этому:

[
  {
    accountName: '1234567890123456789', 
    bank: 'Foo Bank'
  },
  {
    accountName: '9234567890123456789', 
    bank: 'Foo Bank'
  }
]

Как я могу разрешить это? Массив объектов не всегда имеет одинаковую форму, поэтому мне нужна рекурсивная функция, которая удерживает первый ключ исходного объекта и выравнивает значение до тех пор, пока он не перестанет быть объектом.

Ответы [ 4 ]

2 голосов
/ 29 октября 2019

Этот код должен итеративно извлекать самое глубокое значение каждого ключа в каждом объекте:

const processed = data.reduce((result, obj) => {
  return result.concat(Object.keys(obj).reduce((entry, key) => {
      entry[key] = obj[key];
      while (entry[key].value) { entry[key] = entry[key].value; }
      return entry;
    }, {}));
  }, []);
2 голосов
/ 29 октября 2019

Вы можете сделать что-то вроде этого, проверить, является ли value объектом или нет, если этот объект перейдет на более глубокий уровень, иначе используйте значение

let data = [{accountName: {type: 'link',value: {value: '1234567890123456789',to: '/q?Id=1237896540789654',},},bank: {type: 'text',value: 'Foo Bank',},},{accountName: {type: 'link',value: {value: '9234567890123456789',to: '/q?Id=9234567890123456789',},},bank: {type: 'text',value: 'Foo Bank',},},];

let getDeepestValue = obj => {
  let value = obj.value
  while(typeof value == 'object'){
    value = value.value 
  }
  return value
}

let final = data.map(({accountName,bank})=>{
  return{
    accountName: getDeepestValue(accountName),
    bank: getDeepestValue(bank)
  }
})

console.log(final)
2 голосов
/ 29 октября 2019

Существует несколько библиотек, которые могут помочь, но, может быть, что-то подобное будет работать?

results.map(result => ({
    accountName: result.accountName.value.value,
    bank: result.bank.value
}));

За исключением того, что вы сказали "Массив объектов не всегда имеет одинаковую форму", ноЯ не уверен, как решить это. Вы сказали что-то о поиске рекурсивно, означает ли это поиск самой глубокой «ценности» в объекте?

0 голосов
/ 30 октября 2019

Я бы выбрал версию, подобную этой:

// helper functions
const mapObject = (fn) => (o) => Object .fromEntries (
  Object .entries (o) .map (([k, v]) => [k, fn (v)])
)
const map = (fn) => (xs) => xs .map(x => fn (x))

// main functions
const deepestValue = (o) => 
  typeof o .value== "object" ? deepestValue (o .value) : o .value

const transform = map (mapObject (deepestValue))

// demo
const input=[{accountName: {type: "link", value: {value: "1234567890123456789", to: "/q?Id=1237896540789654"}}, bank: {type: "text", value: "Foo Bank"}}, {accountName: {type: "link", value: {value: "9234567890123456789", to: "/q?Id=9234567890123456789"}}, bank: {type: "text", value: "Foo Bank"}}]

console.log (transform (input))

Мы можем построить это поэтапно:

Мы начнем с написания простой рекурсивной deepestValue функции, подобной этой:

const deepestValue = (o) => 
  typeof o .value== "object" ? deepestValue (o .value) : o .value

Это можно использовать для написания нашей функции преобразования следующим образом:

const transform = (xs) => xs .map (x => Object.fromEntries (
  Object .entries (x) .map (([k, v]) => [k, deepestValue (v)])
))

(Если ваша среда не поддерживает относительно новый Object.fromEntries, это очень легко подобрать.)

Мы могли бы остановиться там. Но стоит отметить, что этот танец entries -> map -> fromEntries очень многократно используется. Это в основном отображение функции по свойствам объекта. Возможно, хорошее имя mapObject. Мы можем просто извлечь это и использовать его так:

const mapObject = (fn) => (o) => Object .fromEntries (
  Object .entries (o) .map (([k, v]) => [k, fn (v)])
)

const transform = (xs) => xs .map (mapObject (deepestValue))

Но есть еще одна функция, которую мы могли бы абстрагировать от этого, функция map, которая работает как Array.prototype.map, но которая является подставкойодиночная функция. Это также очень легко написать.

const map = (fn) => (xs) => xs .map (x => fn (x))

(я не пишу просто (fn) => (xs) => xs .map (fn) по причинам, описанным во многих местах, в том числе в Почему parseInt дает NaN с Array # map? .)

Теперь мы можем написать приведенный выше фрагмент кода.

Такие функции, как map и mapObject, могут быть добавлены в наши библиотеки личных утилит для повторного использования в различных местах внаше приложение. Такие библиотеки, как Underscore или Ramda (отказ от ответственности: я автор Ramda) собирают такие вещи в полезные коллекции. Рамда map на самом деле охватывает оба этих случая, поэтому в Рамде мы могли бы написать const transform = map (map (deepestValue)).

Обратите внимание, что я не буду извлекать эти вспомогательные функции на основе единичных случаев. Если бы я никогда не видел шаблон раньше, я был бы совершенно счастлив с первой версией transform. Но я делал подобные вещи достаточно часто, чтобы эта абстракция имела для меня смысл. И я думаю, что это всегда помогает разбить вещи на очень простые кусочки.

...