Извлечение массивов объектов в один массив с помощью ES6 - PullRequest
0 голосов
/ 04 декабря 2018

Я работаю над проектом ReactJS и у меня есть следующие данные JSON:

[
  {
    "sources": [
      {
        "sourceName": "test_demographics",
        "table": "test_demographics_summary"
      }
    ],
    "userId": "test",
    "queryType": {
      "mixedQuery": false,
      "queryTable": "test_a_query"
    }
  },
  {
    "sources": [
      {
        "sourceName": "something_demographics",
        "table": "something_demographics_summary"
      },
      {
        "sourceName": "something_demographics",
        "table": "something_demographics_summary"
      }
    ],
    "userId": "test",
    "queryType": {
      "mixedQuery": false,
      "queryTable": "test_bquery"
    }
  }
]

Я хочу извлечь все объекты в свойстве sources в один массив с дедуплицированными данными.По сути, для приведенных выше данных JSON я хочу массив, подобный следующему:

[
  {
    "sourceName": "test_demographics",
    "table": "test_demographics_summary"
  },
  {
    "sourceName": "something_demographics",
    "table": "something_demographics_summary"
  }
]

Цени любые предложения.

Ответы [ 3 ]

0 голосов
/ 04 декабря 2018

Если вы думаете, что у вас будут различные типы данных, а объекты в sources ране не будут иметь разного порядка своих реквизитов, тогда вы можете использовать Set с Array.reduceи JSON.stringify для преобразования их в строки для сравнения:

const data = [ { "sources": [ { "sourceName": "test_demographics", "table": "test_demographics_summary" } ], "userId": "test", "queryType": { "mixedQuery": false, "queryTable": "test_a_query" } }, { "sources": [ { "sourceName": "something_demographics", "table": "something_demographics_summary" }, { "sourceName": "something_demographics", "table": "something_demographics_summary" } ], "userId": "test", "queryType": { "mixedQuery": false, "queryTable": "test_bquery" } } ]

const exists = (s, v) => {
  const json = JSON.stringify(Object.entries(v))
  return s.has(json) ? true : (s.add(json), false)
}
const getUniques = arr => {
  let merged = data.reduce((r,c) => [...r.sources, ...c.sources]), s = new Set()	
  return merged.reduce((r,c) => !exists(s, c) ? (r.push(c), r) : r, [])
}
console.log(getUniques(data))

Идея состоит в том, чтобы сначала объединить все sources через ES6 spread, а затем с помощью Set уменьшить их, проверив, является ли строковое представление sources уже существует в наборе.Мы добавляем только те, которые ** не ** выходят из набора.

Обратите внимание, что каждый раз, когда вы имеете дело с JSON.stringify и сравнением объекта, вы находитесь в зависимости от порядка свойств в объекте.Вы сравниваете это так, если объект A равен {a: 1, b: 2}, а объект B равен {b: 2, a: 1}, они будут считаться различными, поскольку их строковое представление не будет совпадать вообще.Так что, пока это не ваш сценарий, вы должны с этим справиться.

Если, однако, значения в ваших sources объектах будут только строками , вы также можете рассмотреть возможность использования Array.reduce и сгруппировать по значениям и просто выбрать первый элемент массива, так как вы знаете, что другие дубли:

const data = [ { "sources": [ { "sourceName": "test_demographics", "table": "test_demographics_summary" } ], "userId": "test", "queryType": { "mixedQuery": false, "queryTable": "test_a_query" } }, { "sources": [ { "sourceName": "something_demographics", "table": "something_demographics_summary" }, { "sourceName": "something_demographics", "table": "something_demographics_summary" } ], "userId": "test", "queryType": { "mixedQuery": false, "queryTable": "test_bquery" } } ]

const getUniques = arr => {
   const merged = data.reduce((r,c) => [...r.sources, ...c.sources])	
   return Object.values(merged.reduce((r,c) => {
      r[Object.values(c).join()] = c
      return r
   }, {}))
}
console.log(getUniques(data))
0 голосов
/ 07 декабря 2018

В итоге я сделал следующее:

    // extract sources arrays
    let sources = queryObjects.map(function (queryObject) {
        return queryObject.sources;
    })

    // add sources objects into one array and remove duplicates
    let sourcesArray = sources.reduce((acc, currValue) => {
        return _.uniq(acc.concat(currValue));
    })
0 голосов
/ 04 декабря 2018

Поскольку javascript сравнивает объекты по ссылке, вам нужно придумать способ сравнения по значению.Одним из способов является сериализация объектов и сохранение сериализованной версии в наборе.Здесь вы можете сериализовать, взяв Object.entries(), отсортировав ключи и JSON.stringify их.После того, как вы это сделаете, вам нужно просто просмотреть и добавить то, что вы не видели, к набору и выводу.Что-то вроде:

let arr = [{"sources": [{"sourceName": "test_demographics","table": "test_demographics_summary"}],"userId": "test","queryType": {"mixedQuery": false,"queryTable": "test_a_query"}},{"sources": [{"sourceName": "something_demographics","table": "something_demographics_summary"},{"sourceName": "something_demographics","table": "something_demographics_summary"}],"userId": "test","queryType": {"mixedQuery": false,"queryTable": "test_bquery"}}]

function getUniqueSources(arr){

    let seen = new Set // holds serialized object

    return arr.reduce((arr, item) => {
        item.sources.forEach(source =>{
            // need to sort so key order doesn't matter for equality
            let serial = JSON.stringify(Object.entries(source).sort((a, b) => a[0].localeCompare(b[0])))
            if (!seen.has(serial)) {
                seen.add(serial)
                arr.push(source)
            }
        })
        return arr

    },[])
}

console.log(getUniqueSources(arr))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...