Optimize sorting an Array from another Array - javascript

I have two arrays, one containings some items, and another containings sorted ids of those items like so:
const items = [
{ id: 1, label: 'foo' },
{ id: 2, label: 'bar' },
{ id: 3, label: 'lorem' },
{ id: 4, label: 'ipsum' },
]
const sortedItemIds = [4, 3, 2, 1]
I want to have another array containing items sorted by their id like so:
const sortedItems = [
{ id: 4, label: 'ipsum' },
{ id: 3, label: 'lorem' },
{ id: 2, label: 'bar' },
{ id: 1, label: 'foo' },
]
Note that the order may not be whatever, not asc or desc
I made this piece of code, that works pretty well as it:
let sortedItems = []
sortedItemIds.map((itemId, index) => {
items.map(item) => {
if (item.id === itemId) {
sortedItems[index] = item
}
}
})
I feel like I may run into issues with a large array of items, due to the nested Array.map() functions
Is there a better way / best practice for this scenario?

You could create one object where keys are ids and then use that object get values by id.
const items = [{ id: 1, label: 'foo' },{ id: 2, label: 'bar' },{ id: 3, label: 'lorem' },{ id: 4, label: 'ipsum' }]
const sortedItemIds = [4, 3, 2, 1]
const obj = {}
items.forEach(o => obj[o.id] = o);
const sortedItems = sortedItemIds.map(e => Object.assign({}, obj[e]));
console.log(sortedItems)

You don't need the function map for doing this, just use the find Array.indexOf and Array.sort in order to sort it.
const items = [{ id: 1, label: 'foo' },{ id: 2, label: 'bar' },{ id: 3, label: 'lorem' },{ id: 4, label: 'ipsum' }],
sortedItemIds = [4, 3, 2, 1];
items.sort((a, b) => sortedItemIds.indexOf(a.id) - sortedItemIds.indexOf(b.id));
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

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);

JS/ES6/lodash find index of missing elements of two multidimensional arrays

Assuming that I have 2 multidimensional arrays of objects
const products = [
{
id: 1
name: 'lorem'
},
{
id: 3,
name: 'ipsum'
}
];
const tmp_products = [
{
id: 1
name: 'lorem'
},
{
id: 14,
name: 'porros'
},
{
id: 3,
name: 'ipsum'
},
{
id: 105,
name: 'dolor'
},
{
id: 32,
name: 'simet'
}
];
What is the correct way to find the missing indexes by id property?
I'm expecting an output such as [1,3,4] since those objects are not present in products
I found a similar question but applied to plain arrays:
Javascript find index of missing elements of two arrays
var a = ['a', 'b', 'c'],
b = ['b'],
result = [];
_.difference(a, b).forEach(function(t) {result.push(a.indexOf(t))});
console.log(result);
I'd like to use ES6 or lodash to get this as short as possible
You can use sets to do it quickly:
const productIds = new Set(products.map(v => v.id));
const inds = tmp_products
.map((v, i) => [v, i])
.filter(([v, i]) => !productIds.has(v.id))
.map(([v, i]) => i);
inds // [1, 3, 4]
You can use Array.prototype.reduce function to get the list of missing products' index.
Inside reduce callback, you can check if the product is included in products array or not using Array.prototype.some and based on that result, you can decide to add the product index or not.
const products = [
{
id: 1,
name: 'lorem'
},
{
id: 3,
name: 'ipsum'
}
];
const tmp_products = [
{
id: 1,
name: 'lorem'
},
{
id: 14,
name: 'porros'
},
{
id: 3,
name: 'ipsum'
},
{
id: 105,
name: 'dolor'
},
{
id: 32,
name: 'simet'
}
];
const missingIndex = tmp_products.reduce((acc, curV, curI) => {
if (!products.some((item) => item.id === curV.id && item.name === curV.name)) {
acc.push(curI);
}
return acc;
}, []);
console.log(missingIndex);
With lodash you could use differenceWith:
_(tmp_products)
.differenceWith(products, _.isEqual)
.map(prod => tmp_products.indexOf(prod))
.value()
This may not be great for performance, but it depends on how many items you have. With the size of your arrays this should perform ok.

ES6 : sorting an array based on another array order [duplicate]

This question already has answers here:
Javascript - sort array based on another array
(26 answers)
Closed 2 years ago.
sortedArray = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
unSortedArray = [{id: 8, text : 'abcd'}, {id: 4, text : 'ab'}, {id: 1, text : 'cd'}, {id: 2, text : 'def'}, {id: 3, text : 'abcd'}, {id: 5, text : 'abcd'}]
I want to sort unSortedArray based on items of sortedArray and want only object which has same id as in sortedArray
Result expected
[{id: 1, text : 'cd'}, {id: 2, text : 'def'}, {id: 3, text : 'abcd'}, {id: 4, text : 'abc'}]
I have tried similar suggestions based on similar questions.
Adding link of such question here
You could get a hash table first and then map only wanted items.
var sortedArray = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
unSortedArray = [{ id: 8, text : 'abcd' }, { id: 4, text : 'ab' }, { id: 1, text : 'cd' }, { id: 2, text : 'def' }, { id: 3, text : 'abcd' }, { id: 5, text : 'abcd' }],
items = unSortedArray.reduce((r, o) => (r[o.id] = o, r), {}),
result = sortedArray.map(({ id }) => items[id]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this
let sortedArray = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
let unSortedArray = [
{ id: 8, text: "abcd" },
{ id: 4, text: "ab" },
{ id: 1, text: "cd" },
{ id: 2, text: "def" },
{ id: 3, text: "abcd" },
{ id: 5, text: "abcd" }
];
// Method 1 - Reduce
let sorted = sortedArray
.map(itm => itm.id)
.reduce((acc, id) => acc.concat(unSortedArray.filter(itm => itm.id === id)), []);
console.log(sorted);
// Method 2 - Map + flat
sorted = sortedArray
.map(a => unSortedArray.filter(b => b.id === a.id))
.flat();
;
console.log(sorted);
// Method 3 - flatMap
sorted = sortedArray
.flatMap(a => unSortedArray.filter(b => b.id === a.id))
;
console.log(sorted);

Javascript sort an objects by another array [duplicate]

This question already has answers here:
How do I sort an array of objects based on the ordering of another array?
(9 answers)
Javascript - sort array based on another array
(26 answers)
Closed 4 years ago.
I have two arrays.
itemsArray =
[
{ id: 8, name: 'o'},
{ id: 7, name: 'g'},
{ id: 6, name: 'a'},
{ id: 5, name: 'k'},
{ id: 4, name: 'c'}
]
sortArray = [4,5]
How can i sort itemsArray by sortArray (lodash or pure), but i want to for this:
newArray =
[
{ id: 4, name: 'c'},
{ id: 5, name: 'k'},
{ id: 8, name: 'o'},
{ id: 7, name: 'g'},
{ id: 6, name: 'a'}
]
In a case like this where you want to sort on multiple levels, you need to sort them in descending order of importance inside your sorting function.
In this case we sort regularly on cases where both elements are either in or not in the sorting array.
var itemsArray = [
{ id: 8, name: 'o' },
{ id: 7, name: 'g' },
{ id: 6, name: 'a' },
{ id: 5, name: 'k' },
{ id: 4, name: 'c' }
];
var sortArray = [4, 5];
var sortedItemsArray = itemsArray.sort(function (a, b) {
if (sortArray.includes(a.id) == sortArray.includes(b.id)) { //both or neither are in sort array
return b.id - a.id;
}
else if (sortArray.includes(a.id)) { //only a in sort array
return -1;
}
else { //only b in sort array
return 1;
}
});
console.log(sortedItemsArray);
The above snippet could be expanded in multiple ways, but a popular approach is to separate it into several sorting steps.
var itemsArray = [
{ id: 8, name: 'o' },
{ id: 7, name: 'g' },
{ id: 6, name: 'a' },
{ id: 5, name: 'k' },
{ id: 4, name: 'c' }
];
var sortArray = [4, 5];
function sortId(a, b) {
return b.id - a.id;
}
function sortIdByList(a, b) {
if (sortArray.includes(a.id)) {
return -1;
}
if (sortArray.includes(b.id)) {
return 1;
}
return 0;
}
//TEST
var sortedItemsArray = itemsArray
.sort(sortId)
.sort(sortIdByList);
console.log(sortedItemsArray);
This pattern can be easier to maintain as each step is clearly labeled and the functions can be reused in other sorting cases.
The only downside to this pattern is that you end up iterating over the list multiple times, thus increasing the time to sort. Usually this is a non-issue but on very large lists this can be significant.
Sort by array index only
As the comments points out i misread the question, so my previous two sorting snippets doesn't necessarily give the desired result.
This version sorts only by id index in the sorting array:
var itemsArray = [
{ id: 8, name: 'o' },
{ id: 7, name: 'g' },
{ id: 6, name: 'a' },
{ id: 5, name: 'k' },
{ id: 4, name: 'c' }
];
var sortArray = [4, 5];
//TEST
var sortedItemsArray = itemsArray
.sort(function (a, b) {
//Calculate index value of a
var A = sortArray.indexOf(a.id);
if (A == -1) {
A = sortArray.length;
}
//Calculate index value of b
var B = sortArray.indexOf(b.id);
if (B == -1) {
B = sortArray.length;
}
//Return comparison
return A - B;
});
console.log(sortedItemsArray);
You could take the indices of the array for keeping the relative position and take the special items with a negative index to top for sorting.
Then sort the array by taking the indices.
var array = [{ id: 8, name: 'o' }, { id: 7, name: 'g' }, { id: 6, name: 'a' }, { id: 5, name: 'k' }, { id: 4, name: 'c' }],
sortArray = [4, 5],
indices = array.reduce((r, { id }, i) => (r[id] = i, r), {});
sortArray.forEach((id, i, { length }) => indices[id] = i - length);
array.sort(({ id: a }, { id: b }) => indices[a] - indices[b]);
console.log(array);
console.log(indices);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories