compare Two array and result only the values - javascript

I need to filter an array of objects
const arrayOne = [
{id: 33, name: "fruit"},
{id: 157, name: "car"},
{id: 193, name: "water"},
];
const arrayTwo = [33, 193];
I need only the names in an array (without the key)
Expected output
["fruit", "water"]

1) You can easily achive the result using Map
const arrayOne = [
{ id: 33, name: "fruit" },
{ id: 157, name: "car" },
{ id: 193, name: "water" },
];
const map = new Map();
arrayOne.forEach((o) => map.set(o.id, o.name));
const arrayTwo = [33, 193];
const result = arrayTwo.map((o) => map.get(o));
console.log(result);
2) You can also achieve the result using map and find
const arrayOne = [
{ id: 33, name: "fruit" },
{ id: 157, name: "car" },
{ id: 193, name: "water" },
];
const arrayTwo = [33, 193];
const result = arrayTwo.map((id) => arrayOne.find((o) => o.id === id)?.name);
console.log(result);

you can just simply do
const arrayOne = [
{ id: 33, name: "fruit" },
{ id: 157, name: "car" },
{ id: 193, name: "water" }
];
const arrayTwo = [33, 193];
let keepResult = [];
arrayOne.map((a1) => {
arrayTwo.map((a2) => {
if (a1.id === a2) {
keepResult.push(a1.name);
}
});
});
console.log("result show", keepResult);

const arrayOne = [
{id: 33, name: "fruit"},
{id: 157, name: "car"},
{id: 193, name: "water"},
];
const arrayTwo = [33, 193];
let newArray = arrayOne.filter(item => arrayTwo.includes(item.id)).map(item => item.name)
console.log(newArray);
try this

this function is your solution:
const findNames = () => {
let names = []
arrayOne.forEach(item => {
if (arrayTwo.includes(item.id)) {
names = [...names, item.name]
}
})
return names
}

Here is your compare() function for getting array of names based on two array
const arrayOne = [
{id: 33, name: "fruit"},
{id: 157, name: "car"},
{id: 193, name: "water"},
];
const arrayTwo = [33, 157];
function compare(arrayOne, arrayTwo) {
let result = [];
arrayOne.filter(element => arrayTwo.indexOf(element.id) !== -1 ).forEach(element => { result.push(element.name) });
return result ;
}

Use a flatmap on the first array and include only those members having an id property included in array two.
arrayOne.flatMap(({ id, name }) => arrayTwo.includes(id) ? [name]: []);
const arrayOne = [
{id: 33, name: "fruit"},
{id: 157, name: "car"},
{id: 193, name: "water"},
];
const arrayTwo = [33, 193];
const result = arrayOne.flatMap(({ id, name }) => arrayTwo.includes(id) ? [name]: []);
console.log(result);

Related

Find objects that have duplicate names inside the array in JavaScript

I have an array that I find in the searchName section, and in the resultName section I separate the duplicate names, and in the filters section I want to display the objects that have those duplicate names in the console.log, but an empty array
Please help me to get the answer
const data = [
{id: 1,name: "Liam",age: 20},
{id: 1,name: "Noah",age: 22},
{id: 1,name: "Liam",age: 20},
{id: 1,name: "Elijah",age: 18},
{id: 1,name: "Elijah",age: 18}
]
const searchName = data.map(item => item.name)
console.log(searchName);
const toFindDuplicates = arry => arry.filter((item, index) => arry.indexOf(item) !== index);
const resultName = toFindDuplicates(searchName)
console.log(resultName);
const filters = data.filter(x => x.Name === resultName)
console.log(filters);
Use .includes() to check if the name of an element exists inside the resultName array. You also had a typo: x.name instead of x.Name
const data = [{
id: 1,
name: "Liam",
age: 20
},
{
id: 1,
name: "Noah",
age: 22
},
{
id: 1,
name: "Liam",
age: 20
},
{
id: 1,
name: "Elijah",
age: 18
},
{
id: 1,
name: "Elijah",
age: 18
}
]
const searchName = data.map(item => item.name)
console.log(searchName);
const toFindDuplicates = arry => arry.filter((item, index) => arry.indexOf(item) !== index);
const resultName = toFindDuplicates(searchName)
console.log(resultName);
const filters = data.filter(x => resultName.includes(x.name))
console.log(filters);
You need to fix your filter function.
In your version you trying to compare an array to an string.
What you need to do is something like this:
const filters = data.filter(x => resultName.includes(x.name))
First you can count the names and then fill the array
const data = [
{id: 1,name: "Liam",age: 20},
{id: 1,name: "Noah",age: 22},
{id: 1,name: "Liam",age: 20},
{id: 1,name: "Elijah",age: 18},
{id: 1,name: "Elijah",age: 18}
]
const obj = data.reduce((acc, el) => { acc[el.name] = (acc[el.name] ?? 0) + 1; return acc; }, {});
const all = Object.keys(obj);
const duplicates = Object.entries(obj).filter(el => el[1] > 1).map(el => el[0]);
const uniques = Object.entries(obj).filter(el => el[1] === 1).map(el => el[0]);
console.log(all);
console.log(duplicates);
console.log(uniques);

How to filter an array of object with an array of numbers

Given an array of objects arr1 how can I filter out to a new array the objects that do not have a property equal to any value in the array of numbers arr2
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
// Failed attempt
const newArr = arr1.filter(obj1 => arr2.some(num1 => num1 !== obj1.key))
console.log(newArr)
// Expected: [{ key: 1, name: 'Al' }]
// Received: [
// { key: 1, name: 'Al' },
// { key: 2, name: 'Lo' },
// { key: 3, name: 'Ye' }
// ]
Using your syntax:
You have to match on the somein case it's the same and not different. Then if it matches, do not keep the value.
const arr1 = [
{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr= arr1.filter(x => !arr2.some(y => y === x.key));
console.log(newArr);
Alternative syntax below :
const arr1 = [{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr = arr1.filter(({
key,
}) => !arr2.some(y => y === key));
console.log(newArr);
That said, you should be using Array.includes() like some ppl answered. It's simplier for the same outcome
const arr1 = [{
key: 1,
name: 'Al',
},
{
key: 2,
name: 'Lo',
},
{
key: 3,
name: 'Ye',
},
];
const arr2 = [2, 3];
const newArr = arr1.filter(({
key,
}) => !arr2.includes(key));
console.log(newArr);
You can do this
const newArr = arr1.filter(obj => !arr2.includes(obj.key));
This will work for you:
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
const filtered = arr1.filter(val => !arr2.includes(val.key))
console.log(filtered)
:)
For situations like this Set is also very cool (and for big arrays more performant):
const arr1 = [
{
key: 1,
name: 'Al'
},
{
key: 2,
name: 'Lo'
},
{
key: 3,
name: 'Ye'
}
];
const arr2 = [2, 3]
const arr2Set = new Set(arr2);
const newArr = arr1.filter(obj1 => !arr2Set.has(obj1.key))
console.log(newArr)
You can use indexOf like this:
const newArr = arr1.filter(obj => arr2.indexOf(obj.key) > -1);
You need to filter the arr1 when arr1 element does not exist in arr2, so I think it could be better to use indexOf() like this
const newArr = arr1.filter(obj1 => arr2.indexOf(obj1.key) === -1)
if the element does not exist in arr2 it will return -1 which what you need.

How do we reduce nested arrays?

My object which maps student id with marks is as follows:
[
{id: 111, marks: [{sub: 'eng', mark: 90}, {sub: 'maths', mark: 20}]},
{id: 222},
{id: 333, marks: []},
{id: 444, marks: [{sub: 'eng', mark: 70}]}
]
I would like to reduce it as follows:
{
marks[0]: "0:eng:90", // studentIndex:subject_name:mark
marks[1]: "0:maths:20",
marks[2]: "3:eng:70"
}
In the above result, the key is "marks[]" and the value is a string which is a concatenation of studentIndex, the subject and the mark.
So here 0:eng:90 means that student with index of 0 has obtained 90 marks in english subject
I am using lodash and I have tried the following:
reduce(studentList, (acc, student, studentIndex) => {
map(get(student, 'marks'), (marks) => {
acc[`marks[${keys(acc).length}]`] = `${studentIndex}:${marks.sub}:${marks.mark}`;
});
return acc;
}, {});
Is there any other better way to do this?
Without Lodash
var studentList = [{"id":111,"marks":[{"sub":"eng","mark":90},{"sub":"maths","mark":20}]},{"id":222},{"id":333,"marks":[]},{"id":444,"marks":[{"sub":"eng","mark":70}]}]
var result = studentList.reduce((acc, student, studentIndex) => {
(student.marks || []).map((marks) => {
acc[`marks[${Object.keys(acc).length}]`] = `${studentIndex}:${marks.sub}:${marks.mark}`;
});
return acc;
}, {});
console.log(result)
With Lodash
var studentList = [{"id":111,"marks":[{"sub":"eng","mark":90},{"sub":"maths","mark":20}]},{"id":222},{"id":333,"marks":[]},{"id":444,"marks":[{"sub":"eng","mark":70}]}]
var result = _.reduce(studentList, (acc, student, studentIndex) => {
_.map(student.marks || [], (marks) => {
acc[`marks[${_.keys(acc).length}]`] = `${studentIndex}:${marks.sub}:${marks.mark}`;
});
return acc;
}, {});
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
You can use forEach loop.
const input = [
{id: 111, marks: [{sub: 'eng', mark: 90}, {sub: 'maths', mark: 20}]},
{id: 222, marks: []},
{id: 333, marks: []},
{id: 444, marks: [{sub: 'eng', mark: 70}]}
];
const output = [];
input.forEach(({marks}, i) => {
marks.forEach(({sub, mark}) => {
output.push(`${i}:${sub}:${mark}`);
});
});
console.log(output);
--Edit--
const input = [
{id: 111, marks: [{sub: 'eng', mark: 90}, {sub: 'maths', mark: 20}]},
{id: 222},
{id: 333, marks: []},
{id: 444, marks: [{sub: 'eng', mark: 70}]}
];
const output = {};
let count = 0;
input.forEach((obj, i) => {
if(obj.hasOwnProperty("marks")) {
obj.marks.forEach(({sub, mark}) => {
output[`marks[${count}]`] = `${i}:${sub}:${mark}`;
count++;
});
}
});
console.log(output);
Another shorter way without lodash using map:
var studentList = [
{id: 111, marks: [{sub: 'eng', mark: 90}, {sub: 'maths', mark: 20}]},
{id: 222},
{id: 333, marks: []},
{id: 444, marks: [{sub: 'eng', mark: 70}]}
];
var ac = {};
studentList.map((student, i) => {
if (student.marks && student.marks.length)
student.marks.map(m => ac[`marks[${Object.keys(ac).length}]`] = `${i}:${m.sub}:${m.mark}`);
});
console.log(ac);
With lodash you can iterate the students with _.flatMap(), and map the students' marks to pairs of [key, value]. To generate the key you can use _.uniqueId(). The end result would be an array of pairs, which you can convert to an object with _.fromPairs():
const studentList = [{"id":111,"marks":[{"sub":"eng","mark":90},{"sub":"maths","mark":20}]},{"id":222},{"id":333,"marks":[]},{"id":444,"marks":[{"sub":"eng","mark":70}]}]
const result = _.fromPairs( // convert the array to an object
_.flatMap(studentList, ({ marks }, sIndex) => // iterate the students
_.map(marks, ({ sub, mark }) => [ // iterate the marks
`marks${_.uniqueId() - 1}`, // generate the key
`${sIndex}:${sub}:${mark}` // generate the value
])
)
)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Merge two array of objects based on a key

I have two arrays:
Array 1:
[
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
]
and array 2:
[
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
]
I need to merge these two arrays based on id and get this:
[
{ id: "abdc4051", date: "2017-01-24", name: "ab" },
{ id: "abdc4052", date: "2017-01-22", name: "abc" }
]
How can I do this without iterating trough Object.keys?
You can do it like this -
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let arr3 = arr1.map((item, i) => Object.assign({}, item, arr2[i]));
console.log(arr3);
Use below code if arr1 and arr2 are in a different order:
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let merged = [];
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...(arr2.find((itmInner) => itmInner.id === arr1[i].id))}
);
}
console.log(merged);
Use this if arr1 and arr2 are in a same order
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let merged = [];
for(let i=0; i<arr1.length; i++) {
merged.push({
...arr1[i],
...arr2[i]
});
}
console.log(merged);
You can do this in one line
let arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
let arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
const mergeById = (a1, a2) =>
a1.map(itm => ({
...a2.find((item) => (item.id === itm.id) && item),
...itm
}));
console.log(mergeById(arr1, arr2));
Map over array1
Search through array2 for array1.id
If you find it ...spread the result of array2 into array1
The final array will only contain id's that match from both arrays
This solution is applicable even when the merged arrays have different sizes.
Also, even if the matching keys have different names.
Merge the two arrays by using a Map as follows:
const arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4053", date: "2017-01-22" }
];
const arr2 = [
{ nameId: "abdc4051", name: "ab" },
{ nameId: "abdc4052", name: "abc" }
];
const map = new Map();
arr1.forEach(item => map.set(item.id, item));
arr2.forEach(item => map.set(item.nameId, {...map.get(item.nameId), ...item}));
const mergedArr = Array.from(map.values());
console.log(JSON.stringify(mergedArr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run the stack snippet to see the result:
[
{
"id": "abdc4051",
"date": "2017-01-24",
"nameId": "abdc4051",
"name": "ab"
},
{
"id": "abdc4052",
"date": "2017-01-22",
"nameId": "abdc4052",
"name": "abc"
},
{
"id": "abdc4053",
"date": "2017-01-22"
}
]
Here's an O(n) solution using reduce and Object.assign
const joinById = ( ...lists ) =>
Object.values(
lists.reduce(
( idx, list ) => {
list.forEach( ( record ) => {
if( idx[ record.id ] )
idx[ record.id ] = Object.assign( idx[ record.id ], record)
else
idx[ record.id ] = record
} )
return idx
},
{}
)
)
To use this function for the OP's case, pass in the arrays you want to join to joinById (notice lists is a rest parameter).
let joined = joinById(list1, list2)
Each list gets reduced to a single object where the keys are ids and the values are the objects. If there's a value at the given key already, it gets object.assign called on it and the current record.
Here's the generic O(n*m) solution, where n is the number of records and m is the number of keys. This will only work for valid object keys. You can convert any value to base64 and use that if you need to.
const join = ( keys, ...lists ) =>
lists.reduce(
( res, list ) => {
list.forEach( ( record ) => {
let hasNode = keys.reduce(
( idx, key ) => idx && idx[ record[ key ] ],
res[ 0 ].tree
)
if( hasNode ) {
const i = hasNode.i
Object.assign( res[ i ].value, record )
res[ i ].found++
} else {
let node = keys.reduce( ( idx, key ) => {
if( idx[ record[ key ] ] )
return idx[ record[ key ] ]
else
idx[ record[ key ] ] = {}
return idx[ record[ key ] ]
}, res[ 0 ].tree )
node.i = res[ 0 ].i++
res[ node.i ] = {
found: 1,
value: record
}
}
} )
return res
},
[ { i: 1, tree: {} } ]
)
.slice( 1 )
.filter( node => node.found === lists.length )
.map( n => n.value )
This is essentially the same as the joinById method, except that it keeps an index object to identify records to join. The records are stored in an array and the index stores the position of the record for the given key set and the number of lists it's been found in.
Each time the same key set is encountered, it finds the node in the tree, updates the element at it's index, and the number of times it's been found is incremented.
After joining, the idx object is removed from the array with the slice and any elements that weren't found in each set are removed. This makes it an inner join, you could remove this filter and have a full outer join.
Finally each element is mapped to it's value, and you have the joined arrays.
You could use an arbitrary count of arrays and map on the same index new objects.
var array1 = [{ id: "abdc4051", date: "2017-01-24" }, { id: "abdc4052", date: "2017-01-22" }],
array2 = [{ id: "abdc4051", name: "ab" }, { id: "abdc4052", name: "abc" }],
result = [array1, array2].reduce((a, b) => a.map((c, i) => Object.assign({}, c, b[i])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you have 2 arrays need to be merged based on values even its in different order
let arr1 = [
{ id:"1", value:"this", other: "that" },
{ id:"2", value:"this", other: "that" }
];
let arr2 = [
{ id:"2", key:"val2"},
{ id:"1", key:"val1"}
];
you can do like this
const result = arr1.map(item => {
const obj = arr2.find(o => o.id === item.id);
return { ...item, ...obj };
});
console.log(result);
To merge the two arrays on id, assuming the arrays are equal length:
arr1.map(item => ({
...item,
...arr2.find(({ id }) => id === item.id),
}));
We can use lodash here. _.merge works as you expected. It works with the common key present.
_.merge(array1, array2)
Non of these solutions worked for my case:
missing objects can exist in either array
runtime complexity of O(n)
notes:
I used lodash but it's easy to replace with something else
Also used Typescript (just remove/ignore the types)
import { keyBy, values } from 'lodash';
interface IStringTMap<T> {
[key: string]: T;
}
type IIdentified = {
id?: string | number;
};
export function mergeArrayById<T extends IIdentified>(
array1: T[],
array2: T[]
): T[] {
const mergedObjectMap: IStringTMap<T> = keyBy(array1, 'id');
const finalArray: T[] = [];
for (const object of array2) {
if (object.id && mergedObjectMap[object.id]) {
mergedObjectMap[object.id] = {
...mergedObjectMap[object.id],
...object,
};
} else {
finalArray.push(object);
}
}
values(mergedObjectMap).forEach(object => {
finalArray.push(object);
});
return finalArray;
}
You can use array methods
let arrayA=[
{id: "abdc4051", date: "2017-01-24"},
{id: "abdc4052", date: "2017-01-22"}]
let arrayB=[
{id: "abdc4051", name: "ab"},
{id: "abdc4052", name: "abc"}]
let arrayC = [];
arrayA.forEach(function(element){
arrayC.push({
id:element.id,
date:element.date,
name:(arrayB.find(e=>e.id===element.id)).name
});
});
console.log(arrayC);
//0:{id: "abdc4051", date: "2017-01-24", name: "ab"}
//1:{id: "abdc4052", date: "2017-01-22", name: "abc"}
Here is one-liner (order of elements in array is not important and assuming there is 1 to 1 relationship):
var newArray = array1.map(x=>Object.assign(x, array2.find(y=>y.id==x.id)))
I iterated through the first array and used the .find method on the second array to find a match where the id are equal and returned the result.
const a = [{ id: "abdc4051", date: "2017-01-24" },{ id: "abdc4052", date: "2017-01-22" }];
const b = [{ id: "abdc4051", name: "ab" },{ id: "abdc4052", name: "abc" }];
console.log(a.map(itm => ({...itm, ...b.find(elm => elm.id == itm.id)})));
You can recursively merge them into one as follows:
function mergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if (obj2[p].constructor == Object) {
obj1[p] = this.mergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch (e) {
obj1[p] = obj2[p];
}
}
return obj1;
}
arr1 = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
arr2 = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
mergeRecursive(arr1, arr2)
console.log(JSON.stringify(arr1))
Irrespective of the order you can merge it by,
function merge(array,key){
let map = {};
array.forEach(val=>{
if(map[val[key]]){
map[val[key]] = {...map[val[key]],...val};
}else{
map[val[key]] = val;
}
})
return Object.keys(map).map(val=>map[val]);
}
let b = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
];
let a = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
];
console.log(merge( [...a,...b], 'id'));
An approach if both two arrays have non-intersect items.
const firstArray = [
{ id: 1, name: "Alex", salutation: "Mr." },
{ id: 2, name: "Maria", salutation: "Ms." },
];
const secondArray = [
{ id: 2, address: "Larch Retreat 31", postcode: "123452" },
{ id: 3, address: "Lycroft Close 12D", postcode: "123009" },
];
const mergeArr = (arr1, arr2) => {
const obj = {};
arr1.forEach(item => {
obj[item.id] = item;
});
arr2.forEach(item => {
obj[item.id]
? (obj[item.id] = { ...obj[item.id], ...item })
: (obj[item.id] = item);
});
return Object.values(obj);
};
const output = mergeArr(firstArray, secondArray);
console.log(output);
Python 3 Solution for someone who lands on this page in hope of finding one
def merge(studentDetails, studentMark, merge_key):
student_details = {}
student_marks = {}
for sd, sm in zip(studentDetails, studentMark):
key = sd.pop(merge_key)
student_details[key] = sd
key = sm.pop(merge_key)
student_marks[key] = sm
res = []
for id, val in student_details.items():
# Merge three dictionary together
temp = {**{"studentId": id}, **val, **student_marks[id]}
res.append(temp)
return res
if __name__ == '__main__':
# Test Case 1
studentDetails = [
{"studentId": 1, "studentName": 'Sathish', "gender": 'Male', "age": 15},
{"studentId": 2, "studentName": 'kumar', "gender": 'Male', "age": 16},
{"studentId": 3, "studentName": 'Roja', "gender": 'Female', "age": 15},
{"studentId": 4, "studentName": 'Nayanthara', "gender": 'Female', "age": 16},
]
studentMark = [
{"studentId": 1, "mark1": 80, "mark2": 90, "mark3": 100},
{"studentId": 2, "mark1": 80, "mark2": 90, "mark3": 100},
{"studentId": 3, "mark1": 80, "mark2": 90, "mark3": 100},
{"studentId": 4, "mark1": 80, "mark2": 90, "mark3": 100},
]
# Test Case 2
array1 = [
{"id": "abdc4051", "date": "2017-01-24"},
{"id": "abdc4052", "date": "2017-01-22"}
]
array2 = [
{"id": "abdc4051", "name": "ab"},
{"id": "abdc4052", "name": "abc"}
]
output = merge(studentDetails, studentMark, merge_key="studentId")
[print(a) for a in output]
output = merge(array1, array2, merge_key="id")
[print(a) for a in output]
Output
{'studentId': 1, 'studentName': 'Sathish', 'gender': 'Male', 'age': 15, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 2, 'studentName': 'kumar', 'gender': 'Male', 'age': 16, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 3, 'studentName': 'Roja', 'gender': 'Female', 'age': 15, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 4, 'studentName': 'Nayanthara', 'gender': 'Female', 'age': 16, 'mark1': 80, 'mark2': 90, 'mark3': 100}
{'studentId': 'abdc4051', 'date': '2017-01-24', 'name': 'ab'}
{'studentId': 'abdc4052', 'date': '2017-01-22', 'name': 'abc'}
Well... assuming both arrays are of the same length, I would probably do something like this:
var newArr = []
for (var i = 0; i < array1.length; i++ {
if (array1[i].id === array2[i].id) {
newArr.push({id: array1[i].id, date: array1[i].date, name: array2[i].name});
}
}
I was able to achieve this with a nested mapping of the two arrays and updating the initial array:
member.map(mem => {
return memberInfo.map(info => {
if (info.id === mem.userId) {
mem.date = info.date;
return mem;
}
}
}
There are a lot of solutions available for this, But, We can simply use for loop and if conditions to get merged arrays.
const firstArray = [
{ id: 1, name: "Alex", salutation: "Mr." },
{ id: 2, name: "Maria", salutation: "Ms." },
];
const secondArray = [
{ id: 1, address: "Larch Retreat 31", postcode: "123452" },
{ id: 2, address: "Lycroft Close 12D", postcode: "123009" },
];
let mergedArray: any = [];
for (const arr1 of firstArray) {
for (arr2 doc of secondArray) {
if (arr1.id === arr2.id) {
mergedArray.push({ ...arr1, ...arr2 });
}
}
}
console.log(mergedArray)
Here is converting the best answer (jsbisht) into a function that accepts the keys as arguments.
const mergeArraysByKeyMatch = (array1, array2, key1, key2) => {
const map = new Map();
array1.forEach((item) => map.set(item[key1], item));
array2.forEach((item) =>
map.set(item[key2], { ...map.get(item[key2]), ...item })
);
const merged = Array.from(map.values());
return merged;
};
A Typescript O(n+m) (which could be classified as O(n)) solution; without lodash:
// RequireAtLeastOne from https://stackoverflow.com/questions/40510611/typescript-interface-require-one-of-two-properties-to-exist/49725198#49725198
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<
T,
Exclude<keyof T, Keys>
> &
{
[K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>;
}[Keys];
export const mergeDualArraysOnKey = <
K extends PropertyKey,
T extends RequireAtLeastOne<{ [f in PropertyKey]?: unknown }, K>
>(
key: K,
...lists: [T[], T[]]
): T[] => {
const lookup: { [key in string]: number } = {};
return lists[0].concat(lists[1]).reduce((acc: T[], value: T, i: number) => {
const lookupKey = `${value[key]}`;
if (lookup.hasOwnProperty(lookupKey)) {
acc[lookup[lookupKey]] = Object.assign({}, acc[lookup[lookupKey]], value);
} else {
acc.push(value);
lookup[lookupKey] = acc.length - 1;
}
return acc;
}, []);
};
First concatenates the two arrays and then iterates through the newly created array. It uses a lookup table (object) to store the index of an item in the final merged array which has the same key and merges the objects inplace.
If this needed to be extended to handle more arrays, could use a loop or recursion as a wrapping function:
const mergeArrays = <
K extends PropertyKey,
T extends RequireAtLeastOne<{ [f in PropertyKey]?: unknown }, K>
>(
key: K,
...lists: T[][]
): T[] => {
if (lists.length === 1) {
return lists[0];
}
const l1 = lists.pop() || [];
const l2 = lists.pop() || [];
return mergeArrays(key, mergeDualArraysOnKey(key, l1, l2), ...lists);
};
with usage being:
const arr1 = [
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4052", location: "US" },
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4053", date: "2017-01-24" },
{ id: "abdc4054", date: "2017-01-24" },
{ id: "abdc4055", location: "US" },
];
const arr2 = [
{ id: "abdc4052", date: "2017-01-22" },
{ id: "abdc4052", name: "abc" },
{ id: "abdc4055", date: "2017-01-24" },
{ id: "abdc4055", date: "2017-01-24", name: "abcd" },
];
const arr3 = [{ id: "abdc4056", location: "US" }];
const arr4 = [
{ id: "abdc4056", name: "abcde" },
{ id: "abdc4051", name: "ab--ab" },
];
mergeArrays<
"id",
{
id: string;
date?: string;
location?: string;
name?: string;
}
>("id", arr1, arr2, arr3, arr4)
Base on your example, you can do it this way:
const arrayOne = [
{ id: "abdc4051", date: "2017-01-24" },
{ id: "abdc4052", date: "2017-01-22" }
]
const arrayTwo = [
{ id: "abdc4051", name: "ab" },
{ id: "abdc4052", name: "abc" }
]
const mergeArrays = () => {
arrayOne.forEach((item, i) => {
const matchedFound = arrayTwo.findIndex(a => a.id === item.id);
arrayOne[i] = {
...item,
...matchedFound,
}
});
};
mergeArrays();
console.log(arrayOne);
This is a version when you have an object and an array and you want to merge them and give the array a key value so it fits into the object nicely.
var fileData = [
{ "id" : "1", "filename" : "myfile1", "score" : 33.1 },
{ "id" : "2", "filename" : "myfile2", "score" : 31.4 },
{ "id" : "3", "filename" : "myfile3", "score" : 36.3 },
{ "id" : "4", "filename" : "myfile4", "score" : 23.9 }
];
var fileQuality = [0.23456543,0.13413131,0.1941344,0.7854522];
var newOjbect = fileData.map((item, i) => Object.assign({}, item, {fileQuality:fileQuality[i]}));
console.log(newOjbect);

How to transform an array into an object in javascript

I have an array like this:
[
{ id: “Идент”, name: “Назв”, price: “Сто”, quantity: “Коло” },
[ 1, “продукт 1”, “400”, 5 ],
[ 2, “продукт 2”, “300”, 7 ],
[ 2, “продукт 2”, “300”, 7 ]]
How can I transform it into something like this:
{
items: [
{ name: "Хлеб", id: 1, price: 15.9, quantity: 3 },
{ name: "Масло", id: 2, price: 60, quantity: 1 },
{ name: "Картофель", id: 3, price: 22.6, quantity: 6 },
{ name: "Сыр", id: 4, price:310, quantity: 9 }
]
};
I assume that index 0:id,1:name,2:price,3:quantity. here you go,
var array = [
[12,"abc",232,2],
[12,"abc",232,2],
[12,"abc",232,2],
[12,"abc",232,2]
];
var obj = {};
obj.options = (function(array){
var e = [];
for(i in array){
t = {};
t.id = array[i][0];
t.name = array[i][1];
t.price = array[i][2];
t.quantity = array[i][3];
e.push(t);
}
return e;
})(array);
console.log(obj)
To convert an array with data to an array with objects, you could use another array with keys and iterate it for the assignment of the properties for the new objects.
var data = [{ id: 'id', name: 'name', price: 'price', quantity: 'quantity' }, [0, 'foo', 1.99, 201], [1, 'abc', 2.5, 42], [2, 'baz', 10, 99], [6, 'bar', 21.99, 1]],
keys = Object.keys(data[0]),
result = {
items: data.slice(1).map(function (a) {
var temp = {};
keys.forEach(function (k, i) {
temp[k] = a[i];
});
return temp;
})
};
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories