Javascript: полное внешнее объединение в массиве объектов, используя один ключ - PullRequest
1 голос
/ 23 марта 2020

У меня есть два массива объектов, которые я хочу "Full Outer Join", как в SQL:

Набор данных A:

[ { id: 1, name: "apple", color: "red" }, {id: 2, name: "banana", color: "yellow"} ]

Набор данных B:

[ { id: 1, name: "apple", color: "blue" }, {id: 3, name: "mango", color: "green"} ]

Ожидаемый результат:

[ { id: 1, dataset_a: { id: 1, name: "apple", color: "red" }
         , dataset_b: { id: 1, name: "apple", color: "blue" }
  }
, { id: 2, dataset_a: { id: 2, name: "banana", color: "yellow"}
         , dataset_b: null
  }
, { id: 3, dataset_a: null
         , dataset_b: { id: 3, name: "mango", color: "green"}
  }
]
  • Идентификаторы уникальны.
  • Может использоваться Loda sh.
  • У меня нет ограничений на Версия ES.

Вместо нуля пустой объект тоже будет в порядке. Идентификаторы не обязательно должны повторяться, как показано ниже. Итак, это было бы так же хорошо:

[ { id: 1, dataset_a: { name: "apple", color: "red" }
         , dataset_b: { name: "apple", color: "blue" }
  }
, { id: 2, dataset_a: { name: "banana", color: "yellow"}
         , dataset_b: {}
  }
, { id: 3, dataset_a: {}
         , dataset_b: { name: "mango", color: "green"}
  }
]

Решение Нины Шольц, преобразованное в функцию:

fullOuterJoin(dataset_a_name, dataset_b_name, dataset_a, dataset_b, key) {
    const getNullProperties = keys => Object.fromEntries(keys.map(k => [k, null]));
    var data = { [dataset_a_name]:dataset_a, [dataset_b_name]:dataset_b },
        result = Object
            .entries(data)
            .reduce((r, [table, rows]) => {
                //forEach dynamic destructuring
                rows.forEach(({ [key]:id, ...row }) => {
                    if (!r[id]) r.items.push(r[id] = { [key]:id, ...getNullProperties(r.tables) });
                    r[id][table] = row;
                });
                r.tables.push(table);
                r.items.forEach(item => r.tables.forEach(t => item[t] = item[t] || null));
                return r;
            }, { tables: [], items: [] })
            .items;

    return result;
},

Ответы [ 3 ]

1 голос
/ 23 марта 2020

Фрагмент кода специально для вашей потребности:

const datasetA = [ { id: 1, name: "apple", color: "red" }, {id: 2, name: "banana", color: "yellow"} ]
const datasetB = [ { id: 1, name: "apple", color: "blue" }, {id: 3, name: "mango", color: "green"} ]


const joined = [];

// datasetA
for (let i = 0; i < datasetA.length; i++) {
    let item = {
        id: datasetA[i].id,
        dataset_a: datasetA[i],
    };
    joined.push(item);
}
// datasetB
for (let i = 0; i < datasetB.length; i++) {
    const foundObject = joined.find(d => d.id === datasetB[i].id);
    if (foundObject) {
        foundObject['dataset_b'] = datasetB[i];
    }
    else {
        let item = {
            id: datasetB[i].id,
            dataset_a: {},
            dataset_b: datasetB[i],
        };
        joined.push(item);
    }
}

console.log(joined);
1 голос
/ 23 марта 2020

Вы можете выбрать динамический подход c, сохранить требуемые наборы данных в объекте и выполнить итерации записей из объекта. Затем сгруппируйте по id и получите все элементы обратно.

Этот подход использует объект в виде таблицы ha sh с ключом id и массив в качестве хранилища для набора результатов. Если id неизвестно, используется новый объект с id и ранее использованные ключи со значением null. Затем фактический набор данных добавляется к объекту.

Наконец, для отсутствующих таблиц присваиваются также значения 1010 *.

const
    getNullProperties = keys => Object.fromEntries(keys.map(k => [k, null]));

var dataset_a = [{ id: 1, name: "apple", color: "red" }, { id: 2, name: "banana", color: "yellow" }],
    dataset_b = [{ id: 1, name: "apple", color: "blue" }, { id: 3, name: "mango", color: "green" }],
    data = { dataset_a, dataset_b },
    result = Object
        .entries(data)
        .reduce((r, [table, rows]) => {
            rows.forEach(({ id, ...row }) => {
                if (!r[id]) r.items.push(r[id] = { id, ...getNullProperties(r.tables) });
                r[id][table] = row;
            });
            r.tables.push(table);
            r.items.forEach(item => r.tables.forEach(t => item[t] = item[t] || null));
            return r;
        }, { tables: [], items: [] })
        .items;

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 23 марта 2020
var array1 = [ { id: 1, name: "apple", color: "red" }, {id: 2, name: "banana", color: "yellow"} ]
var array2 = [ { id: 1, name: "apple", color: "blue" }, {id: 3, name: "mango", color: "green"} ]

var array_sum = array1.concat(array2)

var array_result = []

array_sum.forEach(function(candidate, index){
  var obj_id = candidate.id;
  delete candidate.id
  if(array_result.length == 0){
    array_result.push({
      "id": obj_id,
      ["dataset_" + index]: candidate
    })
  }else{
    for(var i=0; i<array_result.length; i++){
      if(array_result[i].id == obj_id){
        array_result[i]["dataset_" + index] = candidate
        break;
      }else if(i == array_result.length - 1){
        array_result.push({
          "id": obj_id,
          ["dataset_" + index]: candidate
        })
      }
    }
  }
})
console.log(array_result)
...