Как я могу динамически скрестить слияние этих массивов JSON на Javascript? - PullRequest
0 голосов
/ 27 августа 2018
var a = [
    {id:'1', age:18, name:'Jaden'},
    {id:'2', age:19, name:'Mark'},
    {id:'3', age:38, name:'Jackson'}
];

var b = [
    {id:'1', job: 'webDev'}, 
    {id:'1', job: 'webDev2'},
    {id:'2', job: 'CEO'}
];

var c = [
    {id:'1', birth: '2000/02/01'},
    {id:'2', birth: '1999/05/12'},
    {id:'3', birth: '1982/05/12'}
];

Я хочу сделать как Результат ..

===================== Результат ========================

[

    {id:'1', age:10, name:'Jaden', job: 'webDev', birth: '1998/02/01'}, 
    {id:'1', age:10, name:'Jaden', job: 'webDev2', birth: '1998/02/01'}, 
    {id:'2', age:15, name:'Mark', job: 'CEO', birth: '2000/05/12'},
    {id:'3', age:38, name:'Jackson', job: '', birth: '1982/05/12'}

]

Я пробовал весь день, но все равно не нашел решения :( и это не соединение, а «ключ» - это идентификатор.

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

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

Это предложение является абстрактным решением, что означает, что оно не ограничено некоторыми заданными другими свойствами, кроме общего id. Все остальные свойства обрабатываются без известных заранее.

var a = [{ id: '1', age: 18, name:'Jaden' }, { id: '2', age: 19, name: 'Mark' }, { id: '3', age: 38, name: 'Jackson' }],
    b = [{ id: '1', job: 'webDev' }, { id: '1', job: 'webDev2' }, { id: '2', job: 'CEO' }],
    c = [{ id: '1', birth: '2000/02/01' }, { id: '2', birth: '1999/05/12'}, { id: '3', birth: '1982/05/12' }],
    result = [a, b, c].reduce((r, a) => {
        var temp = [],
            template = Object.assign(...Object.keys(a[0]).filter(k => k !== 'id').map(k => ({ [k]: '' })));
        a.forEach(o => {
            var t = r.filter(({ id }) => o.id === id);
            temp.push(...(t.length ? t : [{ id: o.id }]).map(p => Object.assign({}, p, template, o)));
        });
        temp.push(...r
            .filter(({ id }) => !temp.some(t => t.id === id))
            .map(p => Object.assign({}, p, template))
        );
        return temp;
    }, []);
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 28 августа 2018

Столкнувшись с подобными проблемами, я всегда стараюсь разбить их на более общие шаги Для этого конкретного случая есть четыре:

1. Группировка по id

Вы упоминаете, что хотите присоединиться к элементам по id. Давайте начнем с сортировки записей по идентификатору.

Общий пример

Вот пример groupBy:

const groupById = xs =>
  xs.reduce(
    (acc, x) => {
      if (!acc[x.id]) acc[x.id] = [];
      acc[x.id].push(x);
      return acc;
    },
    {}
  );
  
  
console.log(
  groupById(
    [{ id: 1, a: 1 }, { id: 1, b: 2 }, { id: 2, a: 1 } ]
  )
);

Если код сложен для понимания, взгляните на некоторые ответы «как сгруппировать массив объектов по свойству» здесь при переполнении стека.

Применительно к вашим данным

var names = [
    {id:'1', age:18, name:'Jaden'},
    {id:'2', age:19, name:'Mark'},
    {id:'3', age:38, name:'Jackson'}
];

var jobs = [
    {id:'1', job: 'webDev'}, 
    {id:'1', job: 'webDev2'},
    {id:'2', job: 'CEO'}
];

var births = [
    {id:'1', birth: '2000/02/01'},
    {id:'2', birth: '1999/05/12'},
    {id:'3', birth: '1982/05/12'}
];


console.log(
  groupById(names),
  groupById(jobs),
  groupById(births)
)



function groupById(xs) {
 return xs.reduce(
    (acc, x) => {
      if (!acc[x.id]) acc[x.id] = [];
      acc[x.id].push(x);
      return acc;
    },
    {}
  );
};

Заметьте, как большинство групп (массивов) имеют только один элемент? Только объект заданий имеет группу из двух заданий. Тем не менее, важно, чтобы все группы имели одинаковый формат: массив.

2. Слияние имени, возраста, работы и рождения.

Теперь, когда у нас есть группы элементов, к которым можно обратиться по их идентификатору, мы можем начать думать о их объединении.

Общий пример

В Javascript есть логика для объединения встроенных объектов! Это Object.assign:

console.log(
  Object.assign(
    { },
    { a: 1 },
    { b: 2 },
    { c: 3, d: 4 }
  )
);

Применительно к вашим данным:

console.log(
  Object.assign(
    { id: null, age: null, name: null, job: null },
    { id:'1', age:18, name:'Jaden'},
    { id:'1', job: 'webDev'}, 
    { id:'1', birth: '2000/02/01'}
  )
);

Обратите внимание, что мы использовали нового пустого человека в качестве первого параметра, чтобы обеспечить наличие всех свойств!

3. Создание «лишних» записей

Теперь, когда мы выяснили первый и последний шаг, нам нужно придумать наборы объектов, которые должны быть объединены. Первый шаг: сгруппируйте все данные, которые мы имеем для определенного человека. Давайте сделаем массив с идентификатором "1":

const dataForPerson1 = [ namesAndAges["1"], jobs["1"], births["1"] ];

Теперь у нас есть вложенный массив:

[
  [ { name: "Jaden", ... } ],
  [ { job: "webDev", ... }, { job: "webDev2", ... } ],
  [ { birth: "1998/02/01" } ]
]

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

Общий пример

const combinations = (xs, ys) => 
  xs.reduce(
    (cs, x) => cs.concat(ys.map(y => [y].concat(x))),
    []
  );


console.log(
  [ ["a"], ["b1", "b2"], ["c"] ]
    .reduce(combinations)
)

Обратите внимание, как мы переходим от четырех записей, разбросанных по трем массивам, к двум комбинациям записей.

Применительно к вашим данным:

const combinations = (xs, ys) => 
  xs.reduce(
    (cs, x) => cs.concat(ys.map(y => [y].concat(x))),
    []
  );

console.log(JSON.stringify(
  [ 
    [ {id:'1', age:18, name:'Jaden'} ],
    [ {id:'1', job: 'webDev'}, 
      {id:'1', job: 'webDev2'} ],
    [ {id:'1', birth: '2000/02/01'} ]
  ].reduce(combinations)
,null, 2));

Если вы внимательно посмотрите на результат, вы увидите, что правильный результат начинает обретать форму!

4. Цикл по всем данным и автоматическая генерация результата

Здесь все это объединяется. Суммировано ( Жирный шагов добавлено):

  • Начните с трех массивов
  • Сгруппируйте каждый массив по id property (1)
  • Цикл по всем найденным id значениям для поиска групп записей (4)
  • Создание всех комбинаций (3)
  • Присоединить каждую запись к одному объекту (2)

Обратите внимание, что большая часть кода не относится к вашему приложению или данным. Конвейер, который мы создаем со ссылками на данные, - это то, что в конечном итоге выполняет конкретную работу!

// GENERIC UTILITIES
const groupById = xs =>
  xs.reduce(
    (acc, x) => {
      if (!acc[x.id]) acc[x.id] = [];
      acc[x.id].push(x);
      return acc;
    },
    {}
  );

const combinations = (xs, ys) => 
  xs.reduce(
    (cs, x) => cs.concat(ys.map(y => [y].concat(x))),
    []
  );
  
const allCombinations = xxs => xxs.length === 1
  ? xxs
  : xxs.reduce(combinations);
  
const merge = proto => obs => Object.assign(
   {}, proto,
   ...obs
);

// OUR DATA
const names = groupById([
    {id:'1', age:18, name:'Jaden'},
    {id:'2', age:19, name:'Mark'},
    {id:'3', age:38, name:'Jackson'}
]);

const jobs = groupById([
    {id:'1', job: 'webDev'}, 
    {id:'1', job: 'webDev2'},
    {id:'2', job: 'CEO'}
]);

const births = groupById([
    {id:'1', birth: '2000/02/01'},
    {id:'2', birth: '1999/05/12'},
    {id:'3', birth: '1982/05/12'}
]);

// DATA SPECIFIC HELPERS
const join = id => [ names[id], jobs[id], births[id] ].filter(x => x);

const allIds = new Set([
  ...Object.keys(names),
  ...Object.keys(jobs),
  ...Object.keys(births)
]);

// OUR APP
const result = Array.from(allIds)
  .map(join)
  .map(allCombinations)
  .reduce((xs, ys) => xs.concat(ys)) // flatten
  .map(merge({ id: null, age: null, name: null, birth: null, job: null }))
  
console.log(result);
.as-console-wrapper { min-height: 100%; }
0 голосов
/ 27 августа 2018

вы можете сделать что-то вроде этого:

let a = [
    {id:'1', age:18, name:'Jaden'},
    {id:'2', age:19, name:'Mark'},
    {id:'3', age:38, name:'Jackson'}
];

let b = [
    {id:'1', job: 'webDev'}, 
    {id:'1', job: 'webDev2'},
    {id:'2', job: 'CEO'}
];

let c = [
    {id:'1', birth: '2000/02/01'},
    {id:'2', birth: '1999/05/12'},
    {id:'3', birth: '1982/05/12'}
];

let res = []

a.forEach(person => {
  let birthDate
  
  // get the birth date of this person from the birth array
  for (let birth of c) {
    if (birth.id === person.id) {
      birthDate = birth.birth
    }
  }
  
  // for each job with this person id create a new entry in the result array
  for (let job of b) {
    if (job.id === person.id) {
      res.push({id: person.id, age: person.age, name: person.name, birth: birthDate, job: job.job})
    }
  }
  
  // if there was no entry for this person (no job) create an entry with no job
  if (res.length === 0 || res[res.length - 1].id !== person.id) {
      res.push({id: person.id, age: person.age, name: person.name, birth: birthDate, job: ''})
  }
  
})

console.log(res)

но, как сказано в комментарии многих людей, вам следует избегать многократного ввода, почти равного : предпочитайте этот формат, используя массив для заданий

let a = [
    {id:'1', age:18, name:'Jaden'},
    {id:'2', age:19, name:'Mark'},
    {id:'3', age:38, name:'Jackson'}
];

let b = [
    {id:'1', job: 'webDev'}, 
    {id:'1', job: 'webDev2'},
    {id:'2', job: 'CEO'}
];

let c = [
    {id:'1', birth: '2000/02/01'},
    {id:'2', birth: '1999/05/12'},
    {id:'3', birth: '1982/05/12'}
];

let res = []

a.forEach(person => {
  let tmp = {id: person.id, age: person.age, name: person.name}

  // get the birth date of this person from the birth array
  for (let birth of c) {
    if (birth.id === person.id) {
      tmp.birth = birth.birth
    }
  }
  
  
  // for each job with this person id create a new entry in the job array of current person
  tmp.job = []
  for (let job of b) {
    if (job.id === person.id) {
      tmp.job.push(job.job)
    }
  }
  
  res.push(tmp)
})

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