Vanilla Javascript объединяет объекты массива JSON во вложенный массив, если совпадает с общим значением - PullRequest
0 голосов
/ 22 марта 2019

Мне не удалось найти решение, идентичное проблеме, которую я пытаюсь решить.Если дубликат, пожалуйста, предоставьте ссылку на решение.

Используя ванильный Javascript, объедините массив объектов, имеющих общее значение.У меня есть файл JSON, и он создаст следующий объект javascript (я не могу изменить исходную структуру).Обратите внимание, что у каждого объекта будет свое вложенное имя и значение.Тем не менее, общим значением является имя [0]

var data = [
  {
    name: [
      'Data 1', // common value
      '1 Jan, 2019', // same value therefore not overwrite/merge
      'hotfix dec'
    ],
    value: [
      'hotfix1.fsfix',
      'hotfix1.txt'
    ]
  },
  {
    name: [
      'Data 1', // common value
      '1 Jan, 2019' // same value therefore not overwrite/merge
    ],
    value: 'data1.jar'
  },
  {
    name: [
      'Data 2',
      '1 Feb, 2019'
    ],
    value: 'data2.fsfix'
  },
  {
    name: [
      'Data 2',
      '1 Feb, 2019'
    ],
    value: 'data2.jar'
  },
  {
    name: [
      'Data 3',
      '1 Mar, 2018'
    ],
    value: 'data3.fsfix'
  }
]

Желаемым результатом будет слияние вложенного объекта с тем же именем [0].

var data = [
  {
    name: [
      'Data 1', // common value
      '1 Jan, 2019', // same value therefore not overwrite/merge
      'hotfix dec'
    ],
    value: [
      'data1.fsfix',
      'data1.txt',
      'data1.jar' // This was added after the merge
    ]
  },
  {
    name: [
      'Data 2',
      '1 Feb, 2019'
    ],
    value: [
      'data2.fsfix',
      'data2.jar' // This was added after the merge
    ]
  },
  {
    name: [
      'Data 3',
      '1 Mar, 2018'
    ],
    value: 'data3.fsfix'
  }
]

Использование этого нового объединенного объектаструктура, я бы создал функцию для цикла каждого набора массивов.Заранее спасибо

Ответы [ 3 ]

1 голос
/ 22 марта 2019

Вы можете ввести данные по имени, используя карту. Затем заполните данные в свойстве value соответствующего значения карты, также соберите все дополнительные значения в массивах name (кроме первых двух записей) и, наконец, извлеките значения карты.

Это работает с линейной сложностью времени:

var data = [{name: ['Data 1', '1 Jan, 2019', 'hotfix dec'],value: ['hotfix1.fsfix','hotfix1.txt']},{name: ['Data 1', '1 Jan, 2019'],value: 'data1.jar'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.fsfix'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.jar'},{name: ['Data 3','1 Mar, 2018'],value: 'data3.fsfix'}];

const map = new Map(data.map(o => 
    [o.name[0], { name: o.name.slice(0,2), value: [] }]));
data.forEach(o => map.get(o.name[0]).value.push(...[].concat(o.value)));
data.forEach(o => map.get(o.name[0]).name.push(...o.name.slice(2)));
const result = Array.from(map.values(), o => o.value.length === 1 
    ? { ...o, value: o.value[0] } : o);

console.log(result);

Функция обратного вызова, переданная в Array.from, является функцией отображения. Нужно только превратить массивы значений только с одной строкой только в эту строку. Если это не требуется, вы можете пропустить этот обратный вызов и просто сделать Array.from(map.values()).

0 голосов
/ 22 марта 2019

Вы также можете использовать reduce и map для создания желаемого результата.Я думаю, что это довольно мощная комбинация в целом.

    const data = [{name: ['Data 1', '1 Jan, 2019', 'hotfix dec'],value: ['hotfix1.fsfix','hotfix1.txt']},{name: ['Data 1', '1 Jan, 2019'],value: 'data1.jar'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.fsfix'},{name: ['Data 2','1 Feb, 2019'],value: 'data2.jar'},{name: ['Data 3','1 Mar, 2018'],value: 'data3.fsfix'}];

    const dataMap = data.reduce((acc, curr)=>{
        id = curr.name[0];
        acc[id] = acc[id] || {
            name: [],
            value: []
        };
        const value = Array.isArray(curr.value) ? curr.value : [curr.value]

        acc[id].name = [...acc[id].name, ...curr.name.filter((i)=>acc[id].name.indexOf(i)===-1)]
        acc[id].value = [...acc[id].value, ...value.filter((i)=>acc[id].value.indexOf(i)===-1)]

        return acc
    },{})
    const result = Object.keys(dataMap).map(key=> {
        const d = dataMap[key];
        d.value = d.value.length===1 ? d.value[0] : d.value
        return d;
    })
0 голосов
/ 22 марта 2019

С некоторыми методами Array, я думаю, вы можете сделать эту работу (непроверенный код ниже, но я думаю, что он должен делать то, что вы хотите):

// Merge matching entries by pushing values from matching objects to each other
data = data.map(entry => {
    let matchingObjects = data.filter(match => {
        return match.name[0] === entry.name[0];
    });
    matchingObjects.forEach(match => {
        if (match !== entry) {
            var flatValue = [entry.value].flat();
            entry.value = flatValue.push.apply(flatValue, [match.value].flat());
        }
    });
});

// Remove duplicates by filtering out all but the first entry of each name[0]
data = data.filter((entry, index) => {
    return index === data.findIndex(match => {
        return match.name[0] === entry.name[0];
    });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...