#javascript #node.js #arrays #ecmascript-6
#javascript #node.js #массивы #ecmascript-6
Вопрос:
У меня есть следующий массив, который считается большим набором данных.
let response1 = [
{ userID: '2222', dataOne: [ [Object], [Object] ] },
{
userID: '6666',
dataOne: [ [Object] ],
dataTwo: [ [Object], [Object] ]
},
{
userID: '11111',
dataOne: [ [Object], [Object] ],
dataTwo: [ [Object] ]
},
{ userID: '4586', dataTwo: [ [Object] ] }
];
У меня есть другой массив, который я получил в результате запроса к базе данных (который также представляет собой большой набор данных)
let dbResponse = [{
"attributes": {
"dob": "19890147",
"gender": "M",
"mobilePhone": "1239000000",
"name": "Ketan Hol",
},
"doctorID": "ds45ds",
"userID": "11111"
},
{
"attributes": {
"dob": "19890386",
"gender": "M",
"mobilePhone": "1239000000",
"name": "Sachin",
},
"doctorID": "erjjkrel",
"userID": "6666"
},
{
"attributes": {
"dob": "19890219",
"gender": "M",
"mobilePhone": "1239000000",
"name": "Vishwas",
},
"doctorID": "dfgfdg",
"userID": "2222"
},
{
"attributes": {
"dob": "19890219",
"gender": "M",
"mobilePhone": "1239000000",
"name": "Jis",
},
"doctorID": "dfgfdg",
"userID": "98645"
},
{
"attributes": {
"dob": "19890219",
"gender": "M",
"mobilePhone": "1239000000",
"name": "Brad",
},
"doctorID": "dfgfdg",
"userID": "4586"
},
{
"attributes": {
"dob": "19890219",
"gender": "M",
"mobilePhone": "1239000000",
"name": "Brad",
},
"doctorID": "dfgfdg",
"userID": "4586"
}
];
Мне нужно добавить такие атрибуты, как dob, name из dbResponse в массив response1 на основе того же идентификатора пользователя.
Все идентификаторы пользователя в массиве response1 должны быть заполнены атрибутами, такими как dob, name из dbResponse. Я не понимаю, как выполнить приведенное ниже в большом наборе данных.
Ожидаемый результат будет таким:
response1 = [
{ userID: '2222', dataOne: [ [Object], [Object] ], dob: '19890219', name: 'Vishwas' },
{
userID: '6666',
dataOne: [ [Object] ],
dataTwo: [ [Object], [Object] ],
dob: '19890386',
name: 'Sachin'
},
{
userID: '11111',
dataOne: [ [Object], [Object] ],
dataTwo: [ [Object] ],
dob: '19890147',
name: 'Ketan Hol'
},
{ userID: '4586', dataTwo: [ [Object] ], dob: '19890219', name: 'Brad' }
];
Каков будет наилучший способ добиться этого с использованием функций es6 для больших наборов данных? Я новичок в этих функциях es6. Любая помощь была бы очень признательна.
Ответ №1:
Подход1
Выполните итерацию dbResponse
для каждого userId
элемента response1
, извлеките объект и скопируйте объект в response1
.
Подход2 (оптимизированная операция)
Поскольку оба являются большими массивами, вам придется выполнять итерацию dbResponse
большое количество раз. Чтобы оптимизировать операцию поиска response1
соответствующего userID
объекта в dbResponse
массиве, вы могли бы сохранить сопоставление, чтобы уменьшить сложность поиска.
const result = dbResponse.reduce((acc, obj) => {
const { userID } = obj
acc[userID] = obj;
return acc;
}, {});
const finalResult = response1.reduce((acc, curr) => {
const { userID } = curr
const dbObj = result[userID] || {}
acc.push({
...curr,
...dbObj
})
return acc;
}, []);
Конечный результат будет в finalResult
Комментарии:
1. Спасибо, но мне не нужен MobilePhone amp; DoctorID, так как мы можем улучшить то же самое?
2. Есть ли какие-либо проблемы при преобразовании в это? const результат = dbResponse.reduce((acc, { атрибуты: { dob, имя }, идентификатор пользователя }) => { acc[Идентификатор пользователя] = { dob, имя, идентификатор пользователя}; вернуть acc; }, {});
3. Вы разрушили свойства текущего объекта. И
finalResult
не будет содержать никаких данных вattributes
ключе, поскольку вы добавили их отдельно. Это будет работать правильно.4. Просто предложение, добавьте значения по умолчанию. Например: если
attributes
ключ не существует в каком-либо объекте, код сломается.5. Вы имели в виду, проверяя условие if? или любой другой хороший метод, который у нас есть?
Ответ №2:
Итак, я проверял это, ответ @mappie довольно хорош, индексированный способ — самый быстрый способ, хотя окончательный результат может быть выполнен с использованием map, а не reduce, лично карта вещей понятнее и кажется похожей по времени. Вы можете видеть, что использование Find действительно медленное по сравнению с другими 2 решениями.
Здесь вы можете найти фрагмент, сравнивающий временные интервалы между методами. решение @mappie, но с использованием Map (но нет проверки на несоответствие между 2 массивами)
const result = dbResponse.reduce((acc, obj) => {
const { userID } = obj;
acc[userID] = obj;
return acc;
}, {});
const finalResult = response1.map((user) => ({
...user,
...result[user.userID].attributes,
}));
/******************************************************************************
* Mock Data Creation tools
*****************************************************************************/
const getRandomBetween = (start, end) =>
Math.floor(Math.random() * (end - start)) start;
const getRandomDOB = () =>
getRandomBetween(1950, 2000).toString()
getRandomBetween(10, 12).toString()
getRandomBetween(10, 29).toString();
const getRandomGender = () => (getRandomBetween(0, 1) === 0 ? "M" : "F");
const getUserIdGenerator = (state) => () => state.userID ;
const getResponseDocument = (userIdGenerator) => ({
userID: userIdGenerator(),
dataOne: "don't care",
});
const getDbResponseDocument = (userIdGenerator) => ({
attributes: {
dob: getRandomDOB(),
gender: getRandomGender(),
mobilePhone: getRandomBetween(1000000000, 9999999999).toString(),
name: "Ketan Hol",
},
doctorID: "ds45ds",
userID: userIdGenerator(),
});
/******************************************************************************
* Mock Data Creation
*****************************************************************************/
const usersAmount = 50000;
const r1UidGen = getUserIdGenerator({ userID: 10000 });
const response1 = Array.from(Array(usersAmount).keys()).map(() =>
getResponseDocument(r1UidGen)
);
const dbRUidGen = getUserIdGenerator({ userID: 10000 });
const dbResponse = Array.from(Array(usersAmount).keys()).map(() =>
getDbResponseDocument(dbRUidGen)
);
/******************************************************************************
* Different ways to merge the arrays
*****************************************************************************/
function methodIndexed() {
const result = dbResponse.reduce((acc, obj) => {
const { userID } = obj;
acc[userID] = obj;
return acc;
}, {});
const finalResult = response1.reduce((acc, curr) => {
const { userID } = curr;
const dbObj = result[userID] || {};
acc.push({
...curr,
...dbObj.attributes,
});
return acc;
}, []);
return finalResu<
}
function methodIndexedMap() {
const usersById = dbResponse.reduce((acc, obj) => {
const { userID } = obj;
acc[userID] = obj;
return acc;
}, {});
const finalResult = response1.map((user) => ({
...user,
...usersById[user.userID].attributes,
}));
return finalResu<
}
const byUserId = (userId) => (item) => item.userID === userId;
function methodFind() {
return response1.map((user) => ({
...user,
...dbResponse.find(byUserId(user.userID)).attributes,
}));
}
const results = [];
/******************************************************************************
* Test Methods
*****************************************************************************/
function testMethod(name, method) {
const title = `Method: "${name}"`;
console.time(title);
const result = method();
console.timeEnd(title);
// assert data validity
if (
!(
result[42].userID === response1[42].userID amp;amp;
result[42].userID === dbResponse[42].userID amp;amp;
result[42].dob === dbResponse[42].attributes.dob
)
) {
throw Error(`Method "${name}" does not produce expected output`);
}
}
// difference between these two are too tight to V8 Runtime Optimizations
// so we run them a few time to stabilize
for (let i = 0; i < 10; i ) {
testMethod("Indexed", methodIndexed);
testMethod("Indexed Map", methodIndexedMap);
}
testMethod("Using Find", methodFind);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Комментарии:
1. Вау, отличное объяснение и свежая пара глаз. Спасибо за ваше драгоценное время.
2. Да,
map
может использоваться вместоreduce
. Хотя уменьшение дает свободу управлять вводом в накопитель, чтоmap
не так. С точки зрения производительности,reduce
иmap
похожи. Один немного превосходит другой в зависимости от операции, выполняемой при обратном вызове.
Ответ №3:
Мы можем использовать Array.map для объединения двух наборов данных, также используя Array.найдите, чтобы сопоставить пользователей из массива response1 с массивом dbResponse.
Затем мы можем использовать Object.assign() для копирования всех свойств из атрибутов в dbUser в пользовательский объект.
let response1 = [ { userID: '2222', dataOne: [ {}, {} ] }, { userID: '6666', dataOne: [ {} ], dataTwo: [ {}, {} ] }, { userID: '11111', dataOne: [ {}, {} ], dataTwo: [ {} ] }, { userID: '4586', dataTwo: [ {} ] } ];
let dbResponse = [{ "attributes": { "dob": "19890147", "gender": "M", "mobilePhone": "1239000000", "name": "Ketan Hol", }, "doctorID": "ds45ds", "userID": "11111" }, { "attributes": { "dob": "19890386", "gender": "M", "mobilePhone": "1239000000", "name": "Sachin", }, "doctorID": "erjjkrel", "userID": "6666" }, { "attributes": { "dob": "19890219", "gender": "M", "mobilePhone": "1239000000", "name": "Vishwas", }, "doctorID": "dfgfdg", "userID": "2222" }, { "attributes": { "dob": "19890219", "gender": "M", "mobilePhone": "1239000000", "name": "Jis", }, "doctorID": "dfgfdg", "userID": "98645" }, { "attributes": { "dob": "19890219", "gender": "M", "mobilePhone": "1239000000", "name": "Brad", }, "doctorID": "dfgfdg", "userID": "4586" }, { "attributes": { "dob": "19890219", "gender": "M", "mobilePhone": "1239000000", "name": "Brad", }, "doctorID": "dfgfdg", "userID": "4586" } ];
function mergeUserData(response, dbResponse) {
return response.map(user => {
// Find the same user in the dbResponse array
let dbUser = dbResponse.find(dbUser => dbUser.userID === user.userID);
if (dbUser) {
// Copy the relevant information
user.name = dbUser.attributes.name;
user.dob = dbUser.attributes.dob;
}
return user;
})
}
console.log("Merged data:", mergeUserData(response1, dbResponse));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Комментарии:
1. Спасибо, но мне не нужен мобильный телефон, поэтому я не могу напрямую передать сам атрибут, верно?
2. В этом случае мы можем просто скопировать соответствующие свойства!