compute similarities in arrays - javascript

I'm busy making filters. Now I want to compare 5 arrays which contain objects. In a computed variable I only want to have the objects that are found in all the arrays.
These are the computed variables that create the different filters (which are arrays that contain objects)
computed:
filteredOnColor () {
this.presentOnColor = []
for (var p = 0; p < this.paintings.length; p++) {
for (var i = 0; i < this.kleur.length; i++) {
if (this.kleur.length > 0 && this.paintings[p].kleur.includes(this.kleur[i])) {
this.presentOnColor.push(this.paintings[p].title)
}
}
}
},
filteredOnTechnique () {
this.presentOnTechnique = []
for (var p = 0; p < this.technique.length; p++) {
for (var i = 0; i < this.technique.length; i++) {
if (this.technique.length > 0 && this.paintings[p].technique.includes(this.technique[i])) {
this.presentOnTechnique.push(this.paintings[p].title)
}
}
}
},
filteredOnStyle () {
this.presentOnStyle = []
for (var p = 0; p < this.style.length; p++) {
for (var i = 0; i < this.style.length; i++) {
if (this.style.length > 0 && this.paintings[p].style.includes(this.style[i])) {
this.presentOnStyle.push(this.paintings[p].title)
}
}
}
},
RAW DATA
presentOnColor: [A,B,C]
presentOnStyle: [B,C,D
presentOnTechnique: [B,C,F]
presentFilter: [B,C]

You could check the arrays if the objects are included in all arrays and filter the arrays by using the common part.
var $scope = { presentOnColor: ['A', 'B', 'C'], presentOnStyle: ['B', 'C', 'D'], presentOnTechnique: ['B', 'C', 'F'] },
presentFilter = [$scope.presentOnColor, $scope.presentOnStyle, $scope.presentOnTechnique].reduce(function(a, b) {
return a.filter(function(c) {
return b.indexOf(c) !== -1;
});
});
console.log(presentFilter);
ES6
var $scope = { presentOnColor: ['A', 'B', 'C'], presentOnStyle: ['B', 'C', 'D'], presentOnTechnique: ['B', 'C', 'F'] },
presentFilter = [$scope.presentOnColor, $scope.presentOnStyle, $scope.presentOnTechnique]
.reduce((a, b) => a.filter(c => b.includes(c)));
console.log(presentFilter);

Here is very nicer more efficient way of solving the issue. I assumed A, B, C as the characters in he array. If this is happened to be the object give me properties of the object. If you get the idea then its okay.
// Given input as these 3 arrays
const presentOnColor = ['A', 'B', 'C']
const resentOnStyle = ['B', 'C', 'D'];
const presentOnTechnique = ['B', 'C', 'F'];
// Expected outcome
// const presentFilter = ['B', 'C'];
const arrayMap = [
...presentOnColor,
...resentOnStyle,
...presentOnTechnique
].reduce((object, item) => {
object[item] = (object[item] || 0) + 1;
return object;
}, {});
const presentFilter = Object.keys(arrayMap).filter(item => arrayMap[item] === 3);
console.log('presentFilter: ', presentFilter);

Related

Sort does not work correctly when using a number [duplicate]

Is it possible to sort and rearrange an array that looks like this:
itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
to match the arrangement of this array:
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Unfortunately, I don’t have any IDs to keep track on. I would need to priority the items-array to match the sortingArr as close as possible.
Update:
Here is the output I’m looking for:
itemsArray = [
['Bob', 'b'],
['Jason', 'c'],
['Henry', 'b'],
['Thomas', 'b']
['Anne', 'a'],
['Andrew', 'd'],
]
Any idea how this can be done?
One-Line answer.
itemsArray.sort(function(a, b){
return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});
Or even shorter:
itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));
Something like:
items = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && item[1] == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})
Here's a shorter code, but it destroys the sorting array:
result = items.map(function(item) {
var n = sorting.indexOf(item[1]);
sorting[n] = '';
return [n, item]
}).sort().map(function(j) { return j[1] })
If you use the native array sort function, you can pass in a custom comparator to be used when sorting the array. The comparator should return a negative number if the first value is less than the second, zero if they're equal, and a positive number if the first value is greater.
So if I understand the example you're giving correctly, you could do something like:
function sortFunc(a, b) {
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}
itemsArray.sort(sortFunc);
Case 1: Original Question (No Libraries)
Plenty of other answers that work. :)
Case 2: Original Question (Lodash.js or Underscore.js)
var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });
Case 3: Sort Array1 as if it were Array2
I'm guessing that most people came here looking for an equivalent to PHP's array_multisort (I did) so I thought I'd post that answer as well. There are a couple options:
1. There's an existing JS implementation of array_multisort(). Thanks to #Adnan for pointing it out in the comments. It is pretty large, though.
2. Write your own. (JSFiddle demo)
function refSort (targetData, refData) {
// Create an array of indices [0, 1, 2, ...N].
var indices = Object.keys(refData);
// Sort array of indices according to the reference data.
indices.sort(function(indexA, indexB) {
if (refData[indexA] < refData[indexB]) {
return -1;
} else if (refData[indexA] > refData[indexB]) {
return 1;
}
return 0;
});
// Map array of indices to corresponding values of the target array.
return indices.map(function(index) {
return targetData[index];
});
}
3. Lodash.js or Underscore.js (both popular, smaller libraries that focus on performance) offer helper functions that allow you to do this:
var result = _.chain(sortArray)
.pairs()
.sortBy(1)
.map(function (i) { return itemArray[i[0]]; })
.value();
...Which will (1) group the sortArray into [index, value] pairs, (2) sort them by the value (you can also provide a callback here), (3) replace each of the pairs with the item from the itemArray at the index the pair originated from.
this is probably too late but, you could also use some modified version of the code below in ES6 style. This code is for arrays like:
var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];
The actual operation :
arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));
The actual operation in ES5 :
arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
return arrayToBeSorted.includes(v);
});
Should result in arrayToBeSorted = [3,5]
Does not destroy the reference array.
function sortFunc(a, b) {
var sortingArr = ["A", "B", "C"];
return sortingArr.indexOf(a.type) - sortingArr.indexOf(b.type);
}
const itemsArray = [
{
type: "A",
},
{
type: "C",
},
{
type: "B",
},
];
console.log(itemsArray);
itemsArray.sort(sortFunc);
console.log(itemsArray);
Why not something like
//array1: array of elements to be sorted
//array2: array with the indexes
array1 = array2.map((object, i) => array1[object]);
The map function may not be available on all versions of Javascript
ES6
const arrayMap = itemsArray.reduce(
(accumulator, currentValue) => ({
...accumulator,
[currentValue[1]]: currentValue,
}),
{}
);
const result = sortingArr.map(key => arrayMap[key]);
More examples with different input arrays
I would use an intermediary object (itemsMap), thus avoiding quadratic complexity:
function createItemsMap(itemsArray) { // {"a": ["Anne"], "b": ["Bob", "Henry"], …}
var itemsMap = {};
for (var i = 0, item; (item = itemsArray[i]); ++i) {
(itemsMap[item[1]] || (itemsMap[item[1]] = [])).push(item[0]);
}
return itemsMap;
}
function sortByKeys(itemsArray, sortingArr) {
var itemsMap = createItemsMap(itemsArray), result = [];
for (var i = 0; i < sortingArr.length; ++i) {
var key = sortingArr[i];
result.push([itemsMap[key].shift(), key]);
}
return result;
}
See http://jsfiddle.net/eUskE/
var sortedArray = [];
for(var i=0; i < sortingArr.length; i++) {
var found = false;
for(var j=0; j < itemsArray.length && !found; j++) {
if(itemsArray[j][1] == sortingArr[i]) {
sortedArray.push(itemsArray[j]);
itemsArray.splice(j,1);
found = true;
}
}
}
http://jsfiddle.net/s7b2P/
Resulting order: Bob,Jason,Henry,Thomas,Anne,Andrew
In case you get here needing to do this with an array of objects, here is an adaptation of #Durgpal Singh's awesome answer:
const itemsArray = [
{ name: 'Anne', id: 'a' },
{ name: 'Bob', id: 'b' },
{ name: 'Henry', id: 'b' },
{ name: 'Andrew', id: 'd' },
{ name: 'Jason', id: 'c' },
{ name: 'Thomas', id: 'b' }
]
const sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Object.keys(itemsArray).sort((a, b) => {
return sortingArr.indexOf(itemsArray[a].id) - sortingArr.indexOf(itemsArray[b].id);
})
let a = ['A', 'B', 'C' ]
let b = [3, 2, 1]
let c = [1.0, 5.0, 2.0]
// these array can be sorted by sorting order of b
const zip = rows => rows[0].map((_, c) => rows.map(row => row[c]))
const sortBy = (a, b, c) => {
const zippedArray = zip([a, b, c])
const sortedZipped = zippedArray.sort((x, y) => x[1] - y[1])
return zip(sortedZipped)
}
sortBy(a, b, c)
For getting a new ordered array, you could take a Map and collect all items with the wanted key in an array and map the wanted ordered keys by taking sifted element of the wanted group.
var itemsArray = [['Anne', 'a'], ['Bob', 'b'], ['Henry', 'b'], ['Andrew', 'd'], ['Jason', 'c'], ['Thomas', 'b']],
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ],
map = itemsArray.reduce((m, a) => m.set(a[1], (m.get(a[1]) || []).concat([a])), new Map),
result = sortingArr.map(k => (map.get(k) || []).shift());
console.log(result);
I hope that I am helping someone, but if you are trying to sort an array of objects by another array on the first array's key, for example, you want to sort this array of objects:
const foo = [
{name: 'currency-question', key: 'value'},
{name: 'phone-question', key: 'value'},
{name: 'date-question', key: 'value'},
{name: 'text-question', key: 'value'}
];
by this array:
const bar = ['text-question', 'phone-question', 'currency-question', 'date-question'];
you can do so by:
foo.sort((a, b) => bar.indexOf(a.name) - bar.indexOf(b.name));
This is what I was looking for and I did for sorting an Array of Arrays based on another Array:
It's On^3 and might not be the best practice(ES6)
function sortArray(arr, arr1){
return arr.map(item => {
let a = [];
for(let i=0; i< arr1.length; i++){
for (const el of item) {
if(el == arr1[i]){
a.push(el);
}
}
}
return a;
});
}
const arr1 = ['fname', 'city', 'name'];
const arr = [['fname', 'city', 'name'],
['fname', 'city', 'name', 'name', 'city','fname']];
console.log(sortArray(arr,arr1));
It might help someone
I had to do this for a JSON payload I receive from an API, but it wasn't in the order I wanted it.
Array to be the reference array, the one you want the second array sorted by:
var columns = [
{last_name: "last_name"},
{first_name: "first_name"},
{book_description: "book_description"},
{book_id: "book_id"},
{book_number: "book_number"},
{due_date: "due_date"},
{loaned_out: "loaned_out"}
];
I did these as objects because these will have other properties eventually.
Created array:
var referenceArray= [];
for (var key in columns) {
for (var j in columns[key]){
referenceArray.push(j);
}
}
Used this with result set from database. I don't know how efficient it is but with the few number of columns I used, it worked fine.
result.forEach((element, index, array) => {
var tr = document.createElement('tr');
for (var i = 0; i < referenceArray.length - 1; i++) {
var td = document.createElement('td');
td.innerHTML = element[referenceArray[i]];
tr.appendChild(td);
}
tableBody.appendChild(tr);
});
let sortedOrder = [ 'b', 'c', 'b', 'b' ]
let itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
a.itemsArray(function (a, b) {
let A = a[1]
let B = b[1]
if(A != undefined)
A = A.toLowerCase()
if(B != undefined)
B = B.toLowerCase()
let indA = sortedOrder.indexOf(A)
let indB = sortedOrder.indexOf(B)
if (indA == -1 )
indA = sortedOrder.length-1
if( indB == -1)
indB = sortedOrder.length-1
if (indA < indB ) {
return -1;
} else if (indA > indB) {
return 1;
}
return 0;
})
This solution will append the objects at the end if the sorting key is not present in reference array
const result = sortingArr.map((i) => {
const pos = itemsArray.findIndex(j => j[1] === i);
const item = itemsArray[pos];
itemsArray.splice(pos, 1);
return item;
});
this should works:
var i,search, itemsArraySorted = [];
while(sortingArr.length) {
search = sortingArr.shift();
for(i = 0; i<itemsArray.length; i++) {
if(itemsArray[i][1] == search) {
itemsArraySorted.push(itemsArray[i]);
break;
}
}
}
itemsArray = itemsArraySorted;
You could try this method.
const sortListByRanking = (rankingList, listToSort) => {
let result = []
for (let id of rankingList) {
for (let item of listToSort) {
if (item && item[1] === id) {
result.push(item)
}
}
}
return result
}
with numerical sortingArr:
itemsArray.sort(function(a, b){
return sortingArr[itemsArray.indexOf(a)] - sortingArr[itemsArray.indexOf(b)];
});
This seems to work for me:
var outputArray=['10','6','8','10','4','6','2','10','4','0','2','10','0'];
var template=['0','2','4','6','8','10'];
var temp=[];
for(i=0;i<template.length;i++) {
for(x=0;x<outputArray.length;x++){
if(template[i] == outputArray[x]) temp.push(outputArray[x])
};
}
outputArray = temp;
alert(outputArray)
Use the $.inArray() method from jQuery. You then could do something like this
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
var newSortedArray = new Array();
for(var i=sortingArr.length; i--;) {
var foundIn = $.inArray(sortingArr[i], itemsArray);
newSortedArray.push(itemsArray[foundIn]);
}
Use intersection of two arrays.
Ex:
var sortArray = ['a', 'b', 'c', 'd', 'e'];
var arrayToBeSort = ['z', 's', 'b', 'e', 'a'];
_.intersection(sortArray, arrayToBeSort)
=> ['a', 'b', 'e']
if 'z and 's' are out of range of first array, append it at the end of result
this.arrToBeSorted = this.arrToBeSorted.sort(function(a, b){
return uppthis.sorrtingByArray.findIndex(x => x.Id == a.ByPramaeterSorted) - uppthis.sorrtingByArray.findIndex(x => x.Id == b.ByPramaeterSorted);
});
You can do something like this:
function getSorted(itemsArray , sortingArr ) {
var result = [];
for(var i=0; i<arr.length; i++) {
result[i] = arr[sortArr[i]];
}
return result;
}
You can test it out here.
Note: this assumes the arrays you pass in are equivalent in size, you'd need to add some additional checks if this may not be the case.
refer link
refer

Javascript - Sorting an array of objects based on another array [duplicate]

Is it possible to sort and rearrange an array that looks like this:
itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
to match the arrangement of this array:
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Unfortunately, I don’t have any IDs to keep track on. I would need to priority the items-array to match the sortingArr as close as possible.
Update:
Here is the output I’m looking for:
itemsArray = [
['Bob', 'b'],
['Jason', 'c'],
['Henry', 'b'],
['Thomas', 'b']
['Anne', 'a'],
['Andrew', 'd'],
]
Any idea how this can be done?
One-Line answer.
itemsArray.sort(function(a, b){
return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});
Or even shorter:
itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));
Something like:
items = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && item[1] == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})
Here's a shorter code, but it destroys the sorting array:
result = items.map(function(item) {
var n = sorting.indexOf(item[1]);
sorting[n] = '';
return [n, item]
}).sort().map(function(j) { return j[1] })
If you use the native array sort function, you can pass in a custom comparator to be used when sorting the array. The comparator should return a negative number if the first value is less than the second, zero if they're equal, and a positive number if the first value is greater.
So if I understand the example you're giving correctly, you could do something like:
function sortFunc(a, b) {
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}
itemsArray.sort(sortFunc);
Case 1: Original Question (No Libraries)
Plenty of other answers that work. :)
Case 2: Original Question (Lodash.js or Underscore.js)
var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });
Case 3: Sort Array1 as if it were Array2
I'm guessing that most people came here looking for an equivalent to PHP's array_multisort (I did) so I thought I'd post that answer as well. There are a couple options:
1. There's an existing JS implementation of array_multisort(). Thanks to #Adnan for pointing it out in the comments. It is pretty large, though.
2. Write your own. (JSFiddle demo)
function refSort (targetData, refData) {
// Create an array of indices [0, 1, 2, ...N].
var indices = Object.keys(refData);
// Sort array of indices according to the reference data.
indices.sort(function(indexA, indexB) {
if (refData[indexA] < refData[indexB]) {
return -1;
} else if (refData[indexA] > refData[indexB]) {
return 1;
}
return 0;
});
// Map array of indices to corresponding values of the target array.
return indices.map(function(index) {
return targetData[index];
});
}
3. Lodash.js or Underscore.js (both popular, smaller libraries that focus on performance) offer helper functions that allow you to do this:
var result = _.chain(sortArray)
.pairs()
.sortBy(1)
.map(function (i) { return itemArray[i[0]]; })
.value();
...Which will (1) group the sortArray into [index, value] pairs, (2) sort them by the value (you can also provide a callback here), (3) replace each of the pairs with the item from the itemArray at the index the pair originated from.
this is probably too late but, you could also use some modified version of the code below in ES6 style. This code is for arrays like:
var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];
The actual operation :
arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));
The actual operation in ES5 :
arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
return arrayToBeSorted.includes(v);
});
Should result in arrayToBeSorted = [3,5]
Does not destroy the reference array.
function sortFunc(a, b) {
var sortingArr = ["A", "B", "C"];
return sortingArr.indexOf(a.type) - sortingArr.indexOf(b.type);
}
const itemsArray = [
{
type: "A",
},
{
type: "C",
},
{
type: "B",
},
];
console.log(itemsArray);
itemsArray.sort(sortFunc);
console.log(itemsArray);
Why not something like
//array1: array of elements to be sorted
//array2: array with the indexes
array1 = array2.map((object, i) => array1[object]);
The map function may not be available on all versions of Javascript
ES6
const arrayMap = itemsArray.reduce(
(accumulator, currentValue) => ({
...accumulator,
[currentValue[1]]: currentValue,
}),
{}
);
const result = sortingArr.map(key => arrayMap[key]);
More examples with different input arrays
I would use an intermediary object (itemsMap), thus avoiding quadratic complexity:
function createItemsMap(itemsArray) { // {"a": ["Anne"], "b": ["Bob", "Henry"], …}
var itemsMap = {};
for (var i = 0, item; (item = itemsArray[i]); ++i) {
(itemsMap[item[1]] || (itemsMap[item[1]] = [])).push(item[0]);
}
return itemsMap;
}
function sortByKeys(itemsArray, sortingArr) {
var itemsMap = createItemsMap(itemsArray), result = [];
for (var i = 0; i < sortingArr.length; ++i) {
var key = sortingArr[i];
result.push([itemsMap[key].shift(), key]);
}
return result;
}
See http://jsfiddle.net/eUskE/
var sortedArray = [];
for(var i=0; i < sortingArr.length; i++) {
var found = false;
for(var j=0; j < itemsArray.length && !found; j++) {
if(itemsArray[j][1] == sortingArr[i]) {
sortedArray.push(itemsArray[j]);
itemsArray.splice(j,1);
found = true;
}
}
}
http://jsfiddle.net/s7b2P/
Resulting order: Bob,Jason,Henry,Thomas,Anne,Andrew
In case you get here needing to do this with an array of objects, here is an adaptation of #Durgpal Singh's awesome answer:
const itemsArray = [
{ name: 'Anne', id: 'a' },
{ name: 'Bob', id: 'b' },
{ name: 'Henry', id: 'b' },
{ name: 'Andrew', id: 'd' },
{ name: 'Jason', id: 'c' },
{ name: 'Thomas', id: 'b' }
]
const sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Object.keys(itemsArray).sort((a, b) => {
return sortingArr.indexOf(itemsArray[a].id) - sortingArr.indexOf(itemsArray[b].id);
})
let a = ['A', 'B', 'C' ]
let b = [3, 2, 1]
let c = [1.0, 5.0, 2.0]
// these array can be sorted by sorting order of b
const zip = rows => rows[0].map((_, c) => rows.map(row => row[c]))
const sortBy = (a, b, c) => {
const zippedArray = zip([a, b, c])
const sortedZipped = zippedArray.sort((x, y) => x[1] - y[1])
return zip(sortedZipped)
}
sortBy(a, b, c)
For getting a new ordered array, you could take a Map and collect all items with the wanted key in an array and map the wanted ordered keys by taking sifted element of the wanted group.
var itemsArray = [['Anne', 'a'], ['Bob', 'b'], ['Henry', 'b'], ['Andrew', 'd'], ['Jason', 'c'], ['Thomas', 'b']],
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ],
map = itemsArray.reduce((m, a) => m.set(a[1], (m.get(a[1]) || []).concat([a])), new Map),
result = sortingArr.map(k => (map.get(k) || []).shift());
console.log(result);
I hope that I am helping someone, but if you are trying to sort an array of objects by another array on the first array's key, for example, you want to sort this array of objects:
const foo = [
{name: 'currency-question', key: 'value'},
{name: 'phone-question', key: 'value'},
{name: 'date-question', key: 'value'},
{name: 'text-question', key: 'value'}
];
by this array:
const bar = ['text-question', 'phone-question', 'currency-question', 'date-question'];
you can do so by:
foo.sort((a, b) => bar.indexOf(a.name) - bar.indexOf(b.name));
This is what I was looking for and I did for sorting an Array of Arrays based on another Array:
It's On^3 and might not be the best practice(ES6)
function sortArray(arr, arr1){
return arr.map(item => {
let a = [];
for(let i=0; i< arr1.length; i++){
for (const el of item) {
if(el == arr1[i]){
a.push(el);
}
}
}
return a;
});
}
const arr1 = ['fname', 'city', 'name'];
const arr = [['fname', 'city', 'name'],
['fname', 'city', 'name', 'name', 'city','fname']];
console.log(sortArray(arr,arr1));
It might help someone
I had to do this for a JSON payload I receive from an API, but it wasn't in the order I wanted it.
Array to be the reference array, the one you want the second array sorted by:
var columns = [
{last_name: "last_name"},
{first_name: "first_name"},
{book_description: "book_description"},
{book_id: "book_id"},
{book_number: "book_number"},
{due_date: "due_date"},
{loaned_out: "loaned_out"}
];
I did these as objects because these will have other properties eventually.
Created array:
var referenceArray= [];
for (var key in columns) {
for (var j in columns[key]){
referenceArray.push(j);
}
}
Used this with result set from database. I don't know how efficient it is but with the few number of columns I used, it worked fine.
result.forEach((element, index, array) => {
var tr = document.createElement('tr');
for (var i = 0; i < referenceArray.length - 1; i++) {
var td = document.createElement('td');
td.innerHTML = element[referenceArray[i]];
tr.appendChild(td);
}
tableBody.appendChild(tr);
});
let sortedOrder = [ 'b', 'c', 'b', 'b' ]
let itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
a.itemsArray(function (a, b) {
let A = a[1]
let B = b[1]
if(A != undefined)
A = A.toLowerCase()
if(B != undefined)
B = B.toLowerCase()
let indA = sortedOrder.indexOf(A)
let indB = sortedOrder.indexOf(B)
if (indA == -1 )
indA = sortedOrder.length-1
if( indB == -1)
indB = sortedOrder.length-1
if (indA < indB ) {
return -1;
} else if (indA > indB) {
return 1;
}
return 0;
})
This solution will append the objects at the end if the sorting key is not present in reference array
const result = sortingArr.map((i) => {
const pos = itemsArray.findIndex(j => j[1] === i);
const item = itemsArray[pos];
itemsArray.splice(pos, 1);
return item;
});
this should works:
var i,search, itemsArraySorted = [];
while(sortingArr.length) {
search = sortingArr.shift();
for(i = 0; i<itemsArray.length; i++) {
if(itemsArray[i][1] == search) {
itemsArraySorted.push(itemsArray[i]);
break;
}
}
}
itemsArray = itemsArraySorted;
You could try this method.
const sortListByRanking = (rankingList, listToSort) => {
let result = []
for (let id of rankingList) {
for (let item of listToSort) {
if (item && item[1] === id) {
result.push(item)
}
}
}
return result
}
with numerical sortingArr:
itemsArray.sort(function(a, b){
return sortingArr[itemsArray.indexOf(a)] - sortingArr[itemsArray.indexOf(b)];
});
This seems to work for me:
var outputArray=['10','6','8','10','4','6','2','10','4','0','2','10','0'];
var template=['0','2','4','6','8','10'];
var temp=[];
for(i=0;i<template.length;i++) {
for(x=0;x<outputArray.length;x++){
if(template[i] == outputArray[x]) temp.push(outputArray[x])
};
}
outputArray = temp;
alert(outputArray)
Use the $.inArray() method from jQuery. You then could do something like this
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
var newSortedArray = new Array();
for(var i=sortingArr.length; i--;) {
var foundIn = $.inArray(sortingArr[i], itemsArray);
newSortedArray.push(itemsArray[foundIn]);
}
Use intersection of two arrays.
Ex:
var sortArray = ['a', 'b', 'c', 'd', 'e'];
var arrayToBeSort = ['z', 's', 'b', 'e', 'a'];
_.intersection(sortArray, arrayToBeSort)
=> ['a', 'b', 'e']
if 'z and 's' are out of range of first array, append it at the end of result
this.arrToBeSorted = this.arrToBeSorted.sort(function(a, b){
return uppthis.sorrtingByArray.findIndex(x => x.Id == a.ByPramaeterSorted) - uppthis.sorrtingByArray.findIndex(x => x.Id == b.ByPramaeterSorted);
});
You can do something like this:
function getSorted(itemsArray , sortingArr ) {
var result = [];
for(var i=0; i<arr.length; i++) {
result[i] = arr[sortArr[i]];
}
return result;
}
You can test it out here.
Note: this assumes the arrays you pass in are equivalent in size, you'd need to add some additional checks if this may not be the case.
refer link
refer

Split Array object into chucks

I have this array in JS
initialArray = [A,B,C,C,D,E,F,F,G,K]
I want to split into:
chucks = [[A,B,C], [C,D,E,F], [F,G,K]]
Duplicate items are separators such as 'C' or 'F'
How to do this split in ES6?
You could reduce the array and add either the value or a new array, depending on the last value.
const
array = ['A','B','C','C','D','E','F','F','G','K'],
result = array.reduce((r, v, i, { [i - 1]: last }) => {
if (v === last) r.push([]);
r[r.length - 1].push(v);
return r;
}, [[]]);
console.log(result);
Fairly straight forward solution using a single for loop and holding the current chunk in a variable to push to.
const initialArray = ['A', 'A', 'B', 'C', 'C', 'D', 'E', 'F', 'F', 'G', 'K', 'K'];
const chunk_at_duplicate = (arr) => {
let chunk = [], res = [chunk];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === arr[i - 1]) {
res.push(chunk = []);
}
chunk.push(arr[i]);
}
return res;
};
console.log(chunk_at_duplicate(initialArray));
Edited: now is based on clones
const initialArray = ["A","B","C","C","D","E","F","F","G","K"];
const chunks = [];
let smallChunk = [];
let index = 0;
while (index < initialArray.length){
smallChunk.push(initialArray[index]);
if (initialArray[index+1] == initialArray[index]){
chunks.push(smallChunk);
smallChunk = [];
}
index++;
}
chunks.push(smallChunk);
console.log(chunks);
You can use for ... of together with initialArray.entries() as follows:
const initialArray = ["A","B","C","C","D","E","F","F","G","K"];
const chunks = [];
let start = 0
for(const [i,v] of initialArray.entries()) {
if(i > 0 && v === initialArray[i-1]) {
chunks.push( initialArray.slice(start,i) );
start = i;
} else if( i === initialArray.length - 1 ) {
chunks.push( initialArray.slice(start) );
}
}
console.log( chunks );

A function to get the intersection elements of any given number of arrays containing strings

I have the following functions that returns the intersection of the elements between some arrays of strings.
Initially it was meant to handle only 2 arrays, but I started having the need for it to handle more than 2, so I added the conditional return to make it recursive.
How can I make it flexible enough so it will be able to handle any number of arrays (equal or greater than 2, of course).
I though about using ...rest parameters, but I don't know how to do this, yet.
function intersection(list1, list2, list3, list4) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (list3 && list4) {
return intersection(result,list3,list4);
}
if (list3) {
return intersection(result,list3);
}
return result;
}
SNIPPET
function intersection(list1, list2, list3, list4) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (list3 && list4) {
return intersection(result,list3,list4);
}
if (list3) {
return intersection(result,list3);
}
return result;
}
const x1 = ['a','b','c','d','e'];
const x2 = ['a','b','c','d'];
const x3 = ['a','b','c'];
const x4 = ['a','b'];
console.log('Intersection(x1,x2,x3,x4): ' + JSON.stringify(intersection(x1,x2,x3,x4)));
console.log('Intersection(x1,x2,x3): ' + JSON.stringify(intersection(x1,x2,x3)));
console.log('Intersection(x1,x2): ' + JSON.stringify(intersection(x1,x2)));
No need for a recursion, you could take rest parameters ... and for getting the intersection a Set and filter against it.
function intersection(...arrays) {
return arrays.reduce((a, b) => a.filter(Set.prototype.has, new Set(b)));
}
console.log(intersection(['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c'], ['a', 'b']));
console.log(intersection(['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c']));
console.log(intersection(['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd']));
Version with recursion
function intersection(a, b = [], ...arrays) {
var i = a.filter(Set.prototype.has, new Set(b));
return arrays.length
? intersection(i, ...arrays)
: i;
}
console.log(intersection(['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c'], ['a', 'b']));
console.log(intersection(['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c']));
console.log(intersection(['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd']));
Nina's answer is of course greater, but I also post to propose a solution based on your own code.
As your function needs at least two lists, then precise them in your argument list. Then, use destructuring for the facultative ones.
Then, if there is at least one facultative list, re-execute your function by specifying the second parameter as the first facultative one. Use Array#shift to remove it from the list. Don't forget to put your new facultative list.
function intersection(list1, list2, ...lists) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (lists.length) {
return intersection(result, lists.shift(), ...lists);
}
return result;
}
const x1 = ['a','b','c','d','e'];
const x2 = ['a','b','c','d'];
const x3 = ['a','b','c'];
const x4 = ['a','b'];
console.log('Intersection(x1,x2,x3,x4): ' + JSON.stringify(intersection(x1,x2,x3,x4)));
console.log('Intersection(x1,x2,x3): ' + JSON.stringify(intersection(x1,x2,x3)));
console.log('Intersection(x1,x2): ' + JSON.stringify(intersection(x1,x2)));
You can create another function which compares two arrays and returns the intersection. In the intersection function, get the arrays passed as a 2D array called lists using Rest parameters. Use reduce to intersect the arrays with compare as the callback
function compare(list1, list2) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
return result
}
function intersection(...lists) {
return lists.reduce(compare)
}
const x1 = ['a','b','c','d','e'];
const x2 = ['a','b','c','d'];
const x3 = ['a','b','c'];
const x4 = ['a','b'];
console.log('Intersection(x1,x2,x3,x4): ' + JSON.stringify(intersection(x1,x2,x3,x4)));
console.log('Intersection(x1,x2,x3): ' + JSON.stringify(intersection(x1,x2,x3)));
console.log('Intersection(x1,x2): ' + JSON.stringify(intersection(x1,x2)));
Note: You can probably simplify the implementation of compare. This is just to demonstrate with your existing code

breaking from a for look inside a reucrsive function

Please see the fiddle.
I am bit stuck with why the loop does not break the way I intended.
input is an object, indexed with some kind of id. And the values are the children ids. so, I am trying to filter out (here it is hard coded as d) a node and its children. For example, for d, there is only one child, h. so, I was expecting an output ['d', 'h']. This is because, once the filter condition met (c === 'd'), it discards all previous value, and just recurse to its children (only h) in this case. Once the recursion to children finished, the break should terminate the for loop. but as I see from the output, the for loop doesn't breaks and continues with (c -> g). How to make this so once the filter met, it only output the node and all its children ['d', 'h'] in this case.
const input = {
a: ['b', 'c'],
b: ['d', 'e', 'f'],
c: ['g'],
d: ['h'],
}
let data = [];
const recur = (d) => {
const ch = input[d]
if (!ch) {
return;
}
for (let i = 0; i < ch.length; i++) {
console.log(data)
const c = ch[i]
data.push(c)
if (c === 'd') {
data = [c];
console.log("reset data", data)
recur(c)
break
}
recur(c)
}
}
recur('a')
console.log("end: ", data)
output: end: ["d", "h", "c", "g"]
This is what I came up with. https://jsfiddle.net/j6s1vouv/4/ There need a way to inform the parent that, the filter is met and should skip the sibling iteration.
const input = {
a: ['b', 'c'],
b: ['d', 'e', 'f'],
c: ['g'],
d: ['h'],
}
const recur = (d) => {
const ch = input[d]
if (!ch) {
return {
data: []
};
}
let out = [];
for (let i = 0; i < ch.length; i++) {
const c = ch[i]
const x = recur(c)
if (x.skip) { // if any of the child met filter
return x
}
if (c === 'd') { // current id met filter
return {
data: [c].concat(x.data),
skip: true
}
}
out = out.concat([c], x.data)
}
return {
data: out
}
}
console.log("end: ", recur('a').data)

Categories