Sorting multidimensional array based on multiple criteria - javascript

I'm trying to figure out an efficient method to sort a multidimensional array based on how many values of another array exist.
Given the following array:
[1,2,3,4,5,6,7,8,9,10]
I am trying to sort another array of arrays based on how many of those values are included.
[
[1,3,5,7,9,22],
[1,200,300,400,500,600],
[1,2,3,4,5,6]
]
So the code I'm trying to get to would return:
[
[1,2,3,4,5,6],
[1,3,5,7,9,22],
[1,200,300,400,500,600]
]
I think what I'm doing is very inefficient and could be written better or more succinctly with a method I'm not aware of?
https://jsfiddle.net/gb3fsLdv/
const compareNums = [1,2,3,4,5,6,7,8,9,10];
let ourData = [
[1,2,3,100,200,300],
[100,200,300,400,500,600],
[1,2,3,5,6,9]
];
function sortArr(compare, data){
let indexMatches = [];
data.map(arr => {
let count = 0;
compare.map(num => {
if(arr.includes(num)){
count++
}
})
indexMatches.push(count);
})
// So now I have indexMatches with a count of how many hits each array has in the correct index order as the original data
// And I can use data to sort them based on these values...
// Little stuck how to relate the two so the same sorting happens to both arrays
}
sortArr(compareNums, ourData);

First convert the given array to set. And then use filter() to get the count of elements included in other array
const data = [
[1,3,5,7,9,22],
[1,200,300,400,500,600],
[1,2,3,4,5,6]
]
let arr = [1,2,3,4,5,6,7,8,9,10];
function getCount(arr, set){
return arr.filter(x => set.has(x)).length
}
function sortOnCount(data, arr){
let set = new Set(arr);
return data.slice(0).sort((a, b) => getCount(b, set) - getCount(a, set))
}
console.log(sortOnCount(data, arr))

Related

Return only value of listed index from an array JavaScript

I'm trying to filter an array based on the listed index in another array.
For example:
const item = ['apple','orange','watermelon','pineapple'];
const index = [1,3];
Based on the index array , I want to return an array of [ 'orange','pineapple']
How do I do that in an efficient way? I tried using comparison between 2 array , but i think it is not very good for efficiency.
You can do map over the index array and just do a regular indexing to look up the item from the item array.
const result = index.map(idx => item[idx]);
No need for comparisons when you already have the indices. You just access them directly instead.
You can do something like this:
const filteredArray = index.map(i => item[i]);
Output:
You can do the following,
const res = [];
item.forEach((item, idx) => { if(index.includes(idx)) res.push(item); });
console.log(res);

Sort array elements on JavaScript

I have an array, each subarray of which contains different positions in different order:
[
["apple(2)", "banana(5)"],
["peach(3)", "banana(1)"],
["apple(1)"]
]
I need to sort it on JavaScript (ES6) and i expect to get an array like this:
[
["apple(2)", "banana(5)", "peach(0)"],
["apple(0)", "banana(1)", "peach(3)"],
["apple(1)", "banana(0)", "peach(0)"]
]
Order of each subarray should be the same. If subarray don't have some position, i need to add it with 0 value. Can i using something like map() or sort() function or need to compare it manually?
Here is functional programming approach, using a Map and reduce:
const data = [['apple(2)', 'banana(5)'],['peach(3)', 'banana(1)'],['apple(1)'],];
// Create a Map with default values for each name, i.e. with "(0)":
let names = new Map(data.flat().map(item => [item.replace(/\d+/, ""), item.replace(/\d+/, "0")]));
let result = data.map(row =>
[...row.reduce((map, item) =>
map.set(item.replace(/\d+/, ""), item), // Overwrite default
new Map(names) // Start with clone of original Map
).values()]
);
console.log(result);
You have to loop over to get the keys used. You then have to loop over a second time to get the fill in the missing keys. There are many ways of doing it, this is one.
var data = [
["apple(2)", "banana(5)"],
["peach(3)", "banana(1)"],
["apple(1)"]
];
// match string and number
var re = /([^(]+)\((\d+)\)/;
// Loop over and find all of the keys
var grouped = data.reduce((info, subset, index) => {
subset.forEach(item => {
// find the key and count
var parts = item.match(re);
// have we seen this key?
if (!info[parts[1]]) {
// if not create an array
info[parts[1]] = Array(data.length).fill(0);
}
// set the key index with the count
info[parts[1]][index] = parts[2];
})
return info;
}, {});
// loop over the groups and fill in the set
Object.entries(grouped).forEach(([key, counts], colIndex) => {
counts
.forEach((cnt, rowIndex) => {
data[rowIndex][colIndex] = `${key}(${cnt})`;
})
});
console.log(data);
First get the unique words. Then traverse array of arrays to check if the word is present or not. If it is not present then make the word according to your condition and if present then put the original word to the tmp array. At last sort it for each iteration. By the way, I used regex replace method to get the word.
const data = [
['apple(2)', 'banana(5)'],
['peach(3)', 'banana(1)'],
['apple(1)'],
];
const words = [...new Set(data.flat().map((x) => x.replace(/[^a-z]/gi, '')))];
const ret = data.map((x) => {
const tmp = [];
const newX = x.map((y) => y.replace(/[^a-z]/gi, ''));
for (let i = 0, l = words.length; i < l; i += 1) {
if (newX.includes(words[i])) tmp.push(x.shift());
else tmp.push(`${words[i]}(0)`);
}
return tmp.sort();
});
console.log(ret);

Taking the lowest number from a list of objects that have dynamic keys

I am creating an object with dynamic keys as seen here:
const myObject = [
{PINO: 1764},
{FANH: 2737},
{WQTR: 1268},
{CICO: 1228}
];
I want to get the key and value with the lowest value, in this case it's {CICO: 1228}.
How I create this object is like so:
let basic = [];
_.map(values, value => {
let result = value[Object.keys(value)].reduce((c, v) => {
// sum up the amounts per key
c[Object.keys(value)] = (c[Object.keys(value)] || 0) + parseInt(v.amount);
return c;
}, {});
basic.push(result);
})
console.log(basic) => [{PINO: 1764}, {FANH: 2737}, {WQTR: 1268}, {CICO: 1228}]
How can I get the lowest number with it's key from the basic object? I tried using sort and taking the lowest number but the keys are created dynamically so I don't think I have anything I can sort against.
This is a pretty inconvenient way to store data since the keys are more-or-less useless and you need to look at the values of each object to do anything. But you can do it if you need to with something like:
const myObject = [
{PINO: 1764},
{FANH: 2737},
{WQTR: 1268},
{CICO: 1228}
];
let least = myObject.reduce((least, current) => Object.values(least)[0] < Object.values(current)[0] ? least : current)
console.log(least)
If it was a large list, you might benefit from converting the array to a different format so you don't need to keep creating the Object.values array.
Iterate the array with Array.reduce(), get the values of the objects via Object.values(), and take the one with the lower number:
const myObject = [
{PINO: 1764},
{FANH: 2737},
{WQTR: 1268},
{CICO: 1228}
];
const result = myObject.reduce((r, o) =>
Object.values(o)[0] < Object.values(r)[0] ? o : r
);
console.log(result);

Javascript - Rearrange array elements in ascending order of elements within each array

I have an array:
arr =
[{"nid":"MIA","keys":[{"sid":"sm1"},{"sid":"sm2"}]},
{"nid":"MID","keys":[{"sid":"sm1"}]},
{"nid":"MIT","keys":[{"sid":"sm1"},{"sid":"sm2"},{"sid":"sm3"},{"sid":"sm4"},{"sid":"sm5"},{"sid":"sm6"},{"sid":"sm7"},{"sid":"sm8"},{"sid":"sm9"},{"sid":"sm10"}]},
{"nid":"MIO","keys":[{"sid":"sm1"},{"sid":"sm2"},{"sid":"sm3"}]},
{"nid":"MIS","keys":[{"sid":"sm1"},{"sid":"sm2"}]},
{"nid":"MIH","keys":[{"sid":"sm1"}]}]
arr consists of 6 elements. Each of these six elements consists of another array keys. I need to rearrange the six elements in ascending order of the number of keys within each. This means that I need the array to be rearranged in this manner:
arr =
[
{"nid":"MID","keys":[{"sid":"sm1"}]},
{"nid":"MIH","keys":[{"sid":"sm1"}]},
{"nid":"MIA","keys":[{"sid":"sm1"},{"sid":"sm2"}]},
{"nid":"MIS","keys":[{"sid":"sm1"},{"sid":"sm2"}]},
{"nid":"MIO","keys":[{"sid":"sm1"},{"sid":"sm2"},{"sid":"sm3"}]},
{"nid":"MIT","keys":[{"sid":"sm1"},{"sid":"sm2"},{"sid":"sm3"},{"sid":"sm4"},{"sid":"sm5"},{"sid":"sm6"},{"sid":"sm7"},{"sid":"sm8"},{"sid":"sm9"},{"sid":"sm10"}]},
]
I tried to get the number of elements within keys of each array element as shown in the code below:
var arrMap = [];
arr.forEach(function(array_) {
key_ = array_.keys;
var count = 0;
key_.forEach(function(arrKey) {
count++;
var keyCode = arrKey.sid;
})
arrMap.push({'nid':array_.nid, 'count': count});
})
console.log(arrMap);
This gave me the following output:
[{"nid":"MIA","count":2},{"nid":"MID","count":1},{"nid":"MIT","count":10},{"nid":"MIO","count":3},{"nid":"MIS","count":2},{"nid":"MIH","count":1}]
Now I am confused as to how I can proceed to rearrange the array using the count of key elements. Any guidance/help would be highly appreciated!
You can try .sort
let arr = [ {"nid":"MIA","keys":[{"sid":"sm1"},{"sid":"sm2"}]},
{"nid":"MID","keys":[{"sid":"sm1"}]},
{"nid":"MIT","keys":[{"sid":"sm1"},{"sid":"sm2"},{"sid":"sm3"},{"sid":"sm4"},{"sid":"sm5"},{"sid":"sm6"},{"sid":"sm7"},{"sid":"sm8"},{"sid":"sm9"},{"sid":"sm10"}]},
{"nid":"MIO","keys":[{"sid":"sm1"},{"sid":"sm2"},{"sid":"sm3"}]},
{"nid":"MIS","keys":[{"sid":"sm1"},{"sid":"sm2"}]},
{"nid":"MIH","keys":[{"sid":"sm1"}]} ];
arr.sort((a, b) => a.keys.length - b.keys.length);
console.log(arr);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
You can achieve this by using sort function of array
arr.sort(function(a,b){return a.keys.length - b.keys.length})

Javascript - Get Array of indices for 'WILL BE' relationship after sort

I have a very simple question. Say I have an array
a = [10,40,30,20,60,50]
After sorting, it would be (assuming I use sort_a = a.sort())
sort_a = [60,50,40,30,20,10]
I want to create an array of indices from a which specify which location in the sorted array that element WILL BE after sorting. From the above example, the result would be
a_sortedindices = [6, 3, 4, 5, 1, 2]
..meaning 10 is in the 6th position when sorted, 40 is in the 3rd position... etc
Pair the values with their current indices
Sort the array of pairs based on the original values
Combine the pairs with their new indices
Sort the new array based on the original indices
Obtain the new indices from the sorted array
let values = [10,40,30,20,60,50];
let indices = values
.map((v, i) => ({ v, i }))
.sort((l, r) => r.v - l.v)
.map(({v, i}, i2) => ({ v, i, i2 }))
.sort((l, r) => l.i - r.i)
.map(p => p.i2);
console.log(indices);
This results in an array of 0-based indices because JavaScript uses 0-based indices. If you want 1-based indices like in your question, you can change p.i2 to p.i2 + 1 in the second to last line.
One of the ways, apart from many to achieve this:
1) Transform the array into another with old indices
2) Sort the array in descending order
3) Create an answer array since you now know the old and new indices.
let a = [10,40,30,20,60,50];
let transformed = a.map((v,i)=> {
return {num:v,old:i};
});
transformed.sort((a,b)=> {
return b.num - a.num;
});
let ans = [];
transformed.forEach((v,i) => {
ans[v.old] = i+1;
});
console.log(ans);
Not sure if this is a trick question or if you're trying to find the most minimal method for achieving this, but you basically already have it. This is what I came up with:
var a = [10,40,30,20,60,50];
var sort_a = a.slice(0).sort((a1,a2) => a2 - a1);
var a_sortedindices = a.map( a1 => sort_a.indexOf(a1) + 1 );
console.log(a_sortedindices);
Walking through it, I'll explain each part.
First, off you have to sort it. Looks like you need reverse sorting, so we'll add an arrow function describing a reverse sort, but before we do that, we'll also clone the array, otherwise we'll lose the original indexes of the values. .slice(0) is a nice way to return a clone of an array
var sort_a = a.slice(0).sort((a1,a2) => a2 - a1);
Then we'll map each value of the origin array. .map() is nice and easy to quickly manipulate each element in an array. We use .indexOf() to figure out where it was at in the original array. We add one to that value because you're not using zero-based indexing.
var a_sortedindices = a.map( a1 => sort_a.indexOf(a1) + 1 );
And voila. You have the sorted indexes.
A naive way of doing this job could be;
var arr = [10,40,30,20,60,50],
idx = arr.map(function(n){return this.indexOf(n)+1;}, arr.slice().sort((a,b) => b-a));
console.log(idx);
where the this argument for the .map() function callback is arr.slice().sort((a,b) => b-a)
// the array to be sorted
var list = [10,20,30,40];
// temporary array holds objects with position and sort-value
var mapped = list.map(function(el, i) {
return { index: i, value: el };
})
// sorting the mapped array
mapped.sort(function(a, b) {
return b.value - a.value;
});
// you can then remap the sorted mapped array to hold just the indices
P.S.: For future reference MDN is your friend

Categories

Resources