Как я могу объединить два массива объектов с двумя разными размерами, используя пару ключ-значение, чтобы объединить их в один массив?

У меня есть два массива объектов, которые выглядят в формате JSON:

   {
  "Arr1":
   [
    { "_id": "firstSub1", "count": 1, "price": 4 },
    { "_id": "firstSub2", "count": 2, "price": 7 },
    { "_id": "firstSub3", "count": 3, "price": 1 }
    { "_id": "firstSub4", "count": 4, "price": 1 }
   ],

    "Arr2":
     [
      { "name": "firstSub1", "date": 05 / 20 / 1998, "type": sometype1 },
      { "name": "firstSub2"  "date": 12 / 22 / 2011, "type": sometype2 },
      { "name": "firstSub3", "date": 09 / 23 / 2004, "type": sometype3 }
      { "name": "firstSub9", "date": 09 / 23 / 2004, "type": sometype9 }
    ]
//Desired Output
    "finalArray":
     [
      { "name": "firstSub1", "date": 05 / 20 / 1998, "type": sometype1, "count": 1, "price": 4 },  
      { "name": "firstSub2"  "date": 12 / 22 / 2011, "type": sometype2, "count": 2, "price": 7 },
      { "name": "firstSub3", "date": 09 / 23 / 2004, "type": sometype3, "count": 3, "price": 1 },
      { "name": "firstSub9", "date": 09 / 23 / 2004, "type": sometype9 },
      { "_id": "firstSub4", "count": 4, "price": 1 }
          ]   

}

Мне нужно сравнить _id в первом массиве и посмотреть, есть ли совпадение с name в Arr2, и сопоставить их, если _id === name.

Я пробовал использовать lodash и его аннулирование, а также такие функции отображения:

  mergeArray() {
    .... //pulling data

    let Arr1 = data['Arr1Data'];
    let Arr2 = data['Arr2Data'];

    let finalArray = Arr2.map((e, _) =>
      (_ = Arr1.find((q) => e.name === q._id)) ?
        { ...e, ..._ } : e)
    console.info(finalArray)
  }

Все данные из Arr2 возвращаются и объединяются только с половиной данных Arr1, мои данные не возвращаются с желаемым результатом... как я могу сопоставить эти два массива и получить объединение и пересечение?

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

Ted Fitzpatrick 06.03.2019 01:23

Как? Я уже пробовал это .. и я получаю неопределенность, когда пытаюсь вызвать e.name

MoreAngularStuff 06.03.2019 01:27
looks this in JSON format: Публикуя вопросы с примерами данных, постарайтесь сделать их достоверными, это поможет другим помочь вам.
Keith 06.03.2019 01:38
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
3
513
4

Ответы 4

Используя vanilla Js, вы можете получить массив уникальных _id и name из обоих массивов, прокрутить его и присоединиться к объекту из обоих массивов, который соответствует текущему id в итерации:

Дедуплицированный массив ids и names :

const ids = [...new Set([...Arr1.map(e => e._id), ...Arr2.map(e => e.name)])];

Цикл для соединения элементов из обоих массивов:

const result = ids.map(e => ({
  ...Arr1.find(o => o._id === e),
  ...Arr2.find(o => o.name === e)
}))

const Arr1 = [{"_id": "firstSub1","count": 1,"price": 4},{"_id": "firstSub2","count": 2,"price": 7},{"_id": "firstSub3","count": 3,  "price": 1}, {"_id": "firstSub4","count": 4,"price": 1}];

const Arr2 = [{"name": "firstSub1","date": "05 / 20 / 1998","type": "sometype1"}, {"name": "firstSub2","date": "12 / 22 / 2011","type": "sometype2"}, {"name": "firstSub3","date": "09 / 23 / 2004","type": "sometype3"}, {"name": "firstSub9","date": "09 / 23 / 2004","type": "sometype9"}];

const ids = [...new Set([...Arr1.map(e => e._id), ...Arr2.map(e => e.name)])];

const result = ids.map(e => ({
  ...Arr2.find(o => o.name === e),
  ...Arr1.find(o => o._id === e)
}))
console.info(result)

РЕДАКТИРОВАТЬ : Вы можете настроить возвращенный объект в .map(), чтобы удалить свойства (например, _id):

const Arr1 = [{"_id": "firstSub1","count": 1,"price": 4},{"_id": "firstSub2","count": 2,"price": 7},{"_id": "firstSub3","count": 3,  "price": 1}, {"_id": "firstSub4","count": 4,"price": 1}];

const Arr2 = [{"name": "firstSub1","date": "05 / 20 / 1998","type": "sometype1"}, {"name": "firstSub2","date": "12 / 22 / 2011","type": "sometype2"}, {"name": "firstSub3","date": "09 / 23 / 2004","type": "sometype3"}, {"name": "firstSub9","date": "09 / 23 / 2004","type": "sometype9"}];

const ids = [...new Set([...Arr1.map(e => e._id), ...Arr2.map(e => e.name)])];

const result = ids.map(e => {
  const obj = {
    ...Arr2.find(o => o.name === e),
    ...Arr1.find(o => o._id === e)
  }
  
  if (obj.name && obj._id) delete obj._id;
  
  return obj;
})
console.info(result)

Отличный ответ Таки. Всего одна настройка, которую они хотят, чтобы _id был удален. Но тем не менее классно.

Bibberty 06.03.2019 01:56

Хороший. что, если желаемый finalArray: ` "finalArray": [ { "name": "firstSub1", "date": 20/05/1998, "type": sometype1, "count": 1, "price": 4 } , { "имя": "firstSub2" "дата": 22 декабря 2011 г., "тип": какой-то тип2, "количество": 2, "цена": 7 }, { "имя": "firstSub3", "дата" : 23 09 2004, "тип": какой-то тип3, "количество": 3, "цена": 1 }, ` как будет использоваться функция удаления для массивов, для которых нет совпадений

MoreAngularStuff 06.03.2019 07:19

Одним из решений является использование Массив.уменьшить(), начиная с accumulator, равного копии Arr2 (JSON.parse(JSON.stringify(Arr2))), чтобы не изменять исходный массив Arr2. Теперь, перебирая Arr1, если мы нашли совпадение, мы добавляем связанные свойства, используя Объект.назначить(), к связанному объекту в accumulator, в противном случае мы помещаем весь объект в accumulator:

const Arr1 = [
    {"_id": "firstSub1", "count": 1, "price": 4},
    {"_id": "firstSub2", "count": 2, "price": 7},
    {"_id": "firstSub3", "count": 3, "price": 1},
    {"_id": "firstSub4", "count": 4, "price": 1}
];

const Arr2 = [
    {"name": "firstSub1", "date": "05/20/1998", "type": "sometype1"},
    {"name": "firstSub2",  "date": "12/22/2011", "type": "sometype2"},
    {"name": "firstSub3", "date": "09/23/2004", "type": "sometype3"},
    {"name": "firstSub9", "date": "09/23/2004", "type": "sometype9"}
];

let res = Arr1.reduce((acc, {_id, count, price}) =>
{
    let fIdx = acc.findIndex(({name}) => name === _id);

    if (fIdx >= 0)
        Object.assign(acc[fIdx], {count, price});
    else
        acc.push({_id, count, price});
        
    return acc;
}, JSON.parse(JSON.stringify(Arr2)));

console.info(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Вы можете отсортировать по name и сравнить имя индекса i + 1, чтобы проверить, следует ли объединить индекс i + 1 и индекс i или у объекта нет пары для слияния.

Например, сортировка по name означает, что следующим объектом/индексом будет пара.

[{name: "firstSub1", count: 1}, {name: "firstSub1", date: "dd / mm / yyyy"}] // Pair found

или

[{name: "firstSub1", count: 1}, {name: "firstSub2", count: 1}] // There is no a pair

Это при условии, что есть максимум одна пара

let obj = {  "Arr1": [{      "_id": "firstSub1",      "count": 1,      "price": 4    },    {      "_id": "firstSub2",      "count": 2,      "price": 7    },    {      "_id": "firstSub3",      "count": 3,      "price": 1    },    {      "_id": "firstSub4",      "count": 4,      "price": 1    }  ],  "Arr2": [{      "name": "firstSub1",      "date": "05 / 20 / 1998",      "type": "sometype1"    },    {      "name": "firstSub2",      "date": "12 / 22 / 2011",      "type": "sometype2"    },    {      "name": "firstSub3",      "date": "09 / 23 / 2004",      "type": "sometype3"    },    {      "name": "firstSub9",      "date": "09 / 23 / 2004",      "type": "sometype9"    }  ]};

// All objects in one array.
let merge = [...obj.Arr2, 
             // The map is to change _id by name, this is used later.
             ...obj.Arr1.map(({_id, count, price}) => ({name: _id, count, price}))]
                  .sort((a, b) => a.name.localeCompare(b.name));

// This approach doesn't mutate the source objects.
let result = [];
for (let i = 0; i < merge.length;) {
  if (merge[i + 1] && merge[i + 1].name === merge[i].name) {
    result.push(Object.assign(Object.create(null), merge[i], merge[i + 1]));
    i++;
  } else result.push(merge[i]);
  i++;
}

console.info(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Вы можете использовать _.flow() lodash для создания функции, которая объединяет массивы, группирует их по name или _id (в зависимости от того, что находится на объекте). Если группа содержит более 1 элемента, она объединяется в один объект, а свойство _id опускается.

const { flow, partialRight: pr, concat, groupBy, map, merge, has, head, omit } = _

const fn = flow(
  concat, // combine to a single array
  pr(groupBy, o => o.name || o._id), // group by the value of name or _id
  pr(map, o => o.length === 1 ? head(o) : _.omit( // if a group contains 2 items merge them, and remove _id
    merge({}, ...o),
    '_id'
  )),
)

const Arr1 = [{"_id": "firstSub1","count": 1,"price": 4},{"_id": "firstSub2","count": 2,"price": 7},{"_id": "firstSub3","count": 3,  "price": 1}, {"_id": "firstSub4","count": 4,"price": 1}]

const Arr2 = [{"name": "firstSub1","date": "05 / 20 / 1998","type": "sometype1"}, {"name": "firstSub2","date": "12 / 22 / 2011","type": "sometype2"}, {"name": "firstSub3","date": "09 / 23 / 2004","type": "sometype3"}, {"name": "firstSub9","date": "09 / 23 / 2004","type": "sometype9"}]

const result = fn(Arr2, Arr1)

console.info(result)
<script src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Следует отдать должное этому ответу. Я также использую его для объединения дубликатов в один массив. fn(Arr1) работает даже с одним аргументом.

Someone Special 27.07.2021 08:16

Другие вопросы по теме