How to correctly check relations inside arrays of objects? - javascript

I have two array of objects. In one I have data on items and its characteristics, and in the other I have
list of categories with the id key.
Both are fetching from an external API so I can't modify them manually.
first array of object:
[{
title: "xxx",
desc: "zzz",
genre_ids: [1, 2, 3]}
second array of object:
[{id: 1,
name: "women"}]
I want to display name's of the gander using second array.
I had two failed attempts:
first approach
{listCategory.map(z => {z.id.includes(item.genre_ids)
return (z.name)} ) }
second approach
{listCategory.filter(cat =>
cat.id === item.genre_ids
).map(categ => {
console.log("categ", categ.name)
return(<p key={uuid()}>{categ}</p>)})}

You can create another array that would be a Map of the first array where you are retrieving the second array data using a find
const firstArr = [{
title: "xxx",
desc: "zzz",
genre_ids: [1, 2, 3]
}]
const secondArr = [
{id: 1,name: "women"},
{id: 2,name: "men"},
{id: 3,name: "other"},
]
const arrWithAllInformations = firstArr.map(item => {
const { title, desc, genre_ids} = item
const genres_full = genre_ids.map(id => secondArr.find(genre => genre.id === id))
return {
title,
desc,
genres: genres_full
}
})
console.log(arrWithAllInformations)
You can then loop through the arrWithAllInformations objects and display the informations as you want.
More consise way :
const firstArr = [
{title: "xxx",desc: "zzz",genre_ids: [1, 2, 3]}
]
const secondArr = [
{id: 1,name: "women"},
{id: 2,name: "men"},
{id: 3,name: "other"},
]
const arrWithAllInformations = firstArr.map(item => ({...item, genres: item.genre_ids.map(id => secondArr.find(genre => genre.id === id))}))
console.log(arrWithAllInformations)

You can use flatMap and a Set to remove duplicates.
const first = [{
title: "xxx",
desc: "zzz",
genre_ids: [1, 2, 3]
}, {
title: "xxx",
desc: "zzz",
genre_ids: [1, 2, 4]
}];
const second = [{
id: 1,
name: "women"
}, {
id: 2,
name: "man"
}, {
id: 7,
name: "non-binary"
}];
const ids = new Set(first.flatMap(({
genre_ids
}) => genre_ids));
const filtered = second.flatMap(({
id,
name
}) => ids.has(id) ? name : []);
console.log(filtered);

You can simply achieve it by just using Array.forEach() method.
Live Demo :
const firstArr = [{
title: "xxx",
desc: "zzz",
genre_ids: [1, 2, 3]
}];
const secondArr = [{
id: 1,
name: "women"
}];
firstArr.forEach(({ genre_ids }) => secondArr.forEach(obj => {
if (genre_ids.includes(obj.id)) {
console.log(obj.name);
}
}));

Related

Filter an array of objects based on another array

I want to filter this array of Object:
const testArray = [{
id: 4,
filters: ["Norway", "Sweden"]
}, {
id: 2,
filters :["Norway", "Sweden"]
}, {
id: 3,
filters:["Denmark", "Sweden"]
}]
with the filter
const myFilter=["Norway", "Sweden"]
However my code just returns []?
What I have tried so far:
const testArray = [{
id: 4,
filters: ["Norway", "Sweden"]
}, {
id: 2,
filters :["Norway", "Sweden"]
}, {
id: 3,
filters:["Denmark", "Sweden"]
}]
const myFilter=["Norway", "Sweden"]
console.log(testArray.filter(e=>e.filters===myFilter))
You can use Array#every to test the equality+ of two arrays as follows:
const output = testArray.filter(
e => e.filters.every(
filter => myFilter.includes(filter)
)
);
const
testArray = [{ id: 4, filters: ["Norway", "Sweden"] }, { id: 2, filters :["Norway", "Sweden"] }, { id: 3, filters:["Denmark", "Sweden"] }],
myFilter = ["Norway", "Sweden"],
output = testArray.filter(
e => e.filters.every(
filter => myFilter.includes(filter)
)
);
console.log(output)
NOTE: Array#every as used here just confirms that every element of each array is in the other, regardless of the order in which the elements appear.

Compare two array of objects and remove objects from first array if a property value is matched

I have 2 array of objects like
const arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
Here, I need to compare both these arrays and remove matching objects from arrayOne, which should finally give
this.arrayOne = [{id: 1, name: 'one'}];
I tried like below but it is removing all objects from the array
this.arrayOne = this.arrayOne.filter(o1 => this.arrayTwo.some(o2 => o1.id === o2.id));
What I am doing wrong here? Please suggest. Thanks
const arrayOne = [
{ id: 1, name: "one" },
{ id: 2, name: "two" },
{ id: 3, name: "three" },
];
const arrayTwo = [
{ id: 2, name: "two" },
{ id: 3, name: "three" },
];
const arrayTwoIds = new Set(arrayTwo.map((el) => el.id));
const arrayOneFiltered = arrayOne.filter((el) => !arrayTwoIds.has(el.id));
console.log(arrayOneFiltered);
// [ { id: 1, name: 'one' } ]
Depending on the size of the array, creating a set can improve performance, as you do not need to loop over arrayTwo arrayOne.length times but only once. After that, you can look up the existence of an id in arrayTwo in constant time.
Yet, as pointed out in another answer, this is not necessary if the arrays are small (like in your example). In this case, you could also use this one-liner:
arrayOne = arrayOne.filter((elOne) => !arrayTwo.some((elTwo) => elOne.id === elTwo.id));
Here, arrayOne would need to be mutable, i.e. defined with let.
You can find it by comparing it with id.
And arrayOne must be a let.
let arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
arrayOne = arrayOne.filter(one => !arrayTwo.find(two => one.id == two.id));
console.log(arrayOne);
const arrayOne = [{
id: 1,
name: 'one'
}, {
id: 2,
name: 'two'
}, {
id: 3,
name: 'three'
}];
const arrayTwo = [{
id: 2,
name: 'two'
}, {
id: 3,
name: 'three'
}];
const arrayTwoId = arrayTwo.map(el => (el.id)); // extract id from arrayTwo
const result = arrayOne.filter(el => !arrayTwoId.includes(el.id));
console.log(result);
Extract all the ids from the arrayTwo.
filter those objects who do not match the array of ids of arrayTwo.
Your way is correct. but you miss the not operation (!) before arrayTwo.some.
So the correct way is this:
const arrayOne = [
{id: 1, name: 'one'},
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
const arrayTwo = [
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
// Shared Items between arrayOne and arrayTwo (this what you done)
const sharedObjects = arrayOne.filter(o1 => arrayTwo.some(o2 => o1.id === o2.id));
console.log(sharedObjects);
// arrayOne - arrayTwo (this is what you want)
const arrayOneUniqueObjects = arrayOne.filter(o1 => !arrayTwo.some(o2 => o1.id === o2.id));
console.log(arrayOneUniqueObjects);
Also, You can find more details here:
bobbyhadz.com/blog/javascript-get-difference-between-two-arrays-of-objects

What is the most efficient way to iterate between two arrays to find matched values?

I need to find objects in array by matching array of ids. Array of ids can be longer or equal to length of array of persons. I made it with forEach loop of persons array and inside used includes method to find matched id but not sure that it is the good approach. Is there a way to optimize searching algorithm?
const ids = [1, 4, 9, 7, 5, 3];
const matchedPersons = [];
const persons = [
{
id: 1,
name: "James"
},
{
id: 2,
name: "Alan"
},
{
id: 3,
name: "Marry"
}
];
persons.forEach((person) => {
if (ids.includes(person.id)) {
matchedPersons.push(person);
}
});
console.log(matchedPersons);
codesanbox
You could take a Set with O(1) for the check.
const
ids = [1, 4, 9, 7, 5, 3],
persons = [{ id: 1, name: "James" }, { id: 2, name: "Alan" }, { id: 3, name: "Marry" }],
idsSet = new Set(ids),
matchedPersons = persons.filter(({ id }) => idsSet.has(id));
console.log(matchedPersons);
you better use filter. it does exactly what it is meant to do:
const ids = [1, 4, 9, 7, 5, 3];
const persons = [
{
id: 1,
name: "James"
},
{
id: 2,
name: "Alan"
},
{
id: 3,
name: "Marry"
}
];
const matchedPersons = persons.filter(({id}) => ids.includes(id))
console.log(matchedPersons)
you can use Map https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
const ids = [1, 4, 9, 7, 5, 3];
const matchedPersons = [];
const persons = [
{
id: 1,
name: "James"
},
{
id: 2,
name: "Alan"
},
{
id: 3,
name: "Marry"
}
];
const personsMap = new Map()
persons.forEach((person) => {
personsMap.set(person.id, person)
});
persons.forEach((person) => {
if (personsMap.has(person.id)) {
matchedPersons.push(personsMap.get(person.id));
}
});
console.log(matchedPersons);

How to sort an array of objects using another array for reference?

i want to sort an array of objects having id each object using another array that only has the ids, for example:
object = [
{id: 2, name: carlos},
{id: 1, name: maria},
{id: 4, name: juan},
{id: 3, name: pepe}, //this is the array that i want to be sorted or create a copy to return it
]
[1,2,3,4,5] //this is the array that i will use as reference to sort the first one
the final result should be:
object = [
{id: 1, name: maria},
{id: 2, name: carlos},
{id: 3, name: pepe},
{id: 4, name: juam}, //this is the array that i want to be sorted or create a copy to return it
]
im using two maps, but im always getting and array with undefined:
array_to_be_sorted.map((objects) => {
array_reference.map((id) => {
if (objects.id === id) {
return {...objects}
}
}
}
im using map cause think is the best way for bigs array, because im building a music player, so dont know how many tracks the does the user has
You could use Array.prototype.sort() method to get the result.
const data = [
{ id: 2, name: 'carlos' },
{ id: 1, name: 'maria' },
{ id: 4, name: 'juan' },
{ id: 3, name: 'pepe' },
];
const order = [1, 2, 3, 4, 5];
data.sort((x, y) => order.indexOf(x.id) - order.indexOf(y.id));
console.log(data);
Another solution using Map Object which is faster than the first one.
const data = [
{ id: 2, name: 'carlos' },
{ id: 1, name: 'maria' },
{ id: 4, name: 'juan' },
{ id: 3, name: 'pepe' },
];
const order = [1, 2, 3, 4, 5];
const map = new Map();
order.forEach((x, i) => map.set(x, i));
data.sort((x, y) => map.get(x.id) - map.get(y.id));
console.log(data);
Why not just use Array.prototpye.sort()? It's easy and fast.
const pre = document.querySelector('pre');
let object = [
{id: 2, name: 'carlos'},
{id: 1, name: 'maria'},
{id: 4, name: 'juan'},
{id: 3, name: 'pepe'}
];
const criteria = [1,2,3,4,5];
pre.innerText = 'object:' + JSON.stringify(object, null, 2) + '\n\n';
object.sort((a, b) => {
return criteria[a.id] - criteria[b.id];
});
pre.innerText += 'sorted object:' + JSON.stringify(object, null, 2);
Sort an array using criteria from a second array:
<pre></pre>
You can take advantage of Schwartzian transform and sort data based on another array.
const data = [ { id: 2, name: 'carlos' }, { id: 1, name: 'maria' }, { id: 4, name: 'juan' }, { id: 3, name: 'pepe' }, ],
order = [4, 2, 3, 1, 5],
result = data.map(o => {
const index = order.indexOf(o.id);
return [index, o];
})
.sort((a, b) => a[0] - b[0])
.map(([, o]) => o);
console.log(result);

Set order to array of object in javascript

I need to find a simplest way for setting order to array of objects.
For example, there is an array:
var array = [
{id: 1, name: "Matt"},
{id: 2, name: "Jack"},
{id: 3, name: "Morgan"},
{id: 4, name: "Bruce"}
];
and I have provided
var order = [1,4,2,3];
which refers to object id property of array items.
Now I need to reorder array so it should be like:
var array = [
{id: 1, name: "Matt"},
{id: 4, name: "Bruce"},
{id: 2, name: "Jack"},
{id: 3, name: "Morgan"}
]
Use Array#sort method for sorting and inside custom sort function use Array#indexOf method to get index.
var array = [{
id: 1,
name: "Matt"
}, {
id: 2,
name: "Jack"
}, {
id: 3,
name: "Morgan"
}, {
id: 4,
name: "Bruce"
}];
var order = [1, 4, 2, 3];
array.sort(function(a, b) {
// sort based on the index in order array
return order.indexOf(a.id) - order.indexOf(b.id);
})
console.log(array);
You can also use reduce() on [1,4,2,3] array to return object where keys will be elements and values will be index of each element and then sort by that object.
var array = [
{id: 1, name: "Matt"},
{id: 2, name: "Jack"},
{id: 3, name: "Morgan"},
{id: 4, name: "Bruce"}
];
var s = [1,4,2,3].reduce((r, e, i) => {return r[e] = i, r}, {});
var result = array.sort(function(a, b) {
return s[a.id] - s[b.id];
});
console.log(result)
I guess anything that involves sort can not be more efficient than an O(2n) solution. So i would like to do this job with two reduces as follows;
var arr = [{id: 1, name: "Matt"}, {id: 2, name: "Jack"}, {id: 3, name: "Morgan"}, {id: 4, name: "Bruce"}],
order = [1,4,2,3],
lut = order.reduce((t,e,i) => (t[e] = i,t),{}),
result = arr.reduce((res,obj) => (res[lut[obj.id]] = obj, res) ,[]);
console.log(result);

Categories