How to push elements to a 3D array (Javascript) - javascript

I have an object
1:a
2:b
3:c
4:d
5:e
6:f
7:g
8:h
9:i
I want to make a 3D array, like
[
[ [a], [b], [c] ],
[ [d], [e], [f] ],
[ [g], [h], [i] ]
]
Is it possible to write a for-loop to push first three letters to an 3D array, than second three letters and third at the end (like in example)?

You can first sort array of Object.keys() and then use reduce() to create new array by each 3 keys.
var obj = {1: 'a',2: 'b',3: 'c',4: 'd',5: 'e',6: 'f',7: 'g',8: 'h',9: 'i',}
var result = Object.keys(obj).sort((a, b) => a - b).reduce(function(r, e, i) {
if(i % 3 == 0) r.push([]);
r[r.length - 1].push([obj[e]])
return r;
}, [])
console.log(result)

As per #Andreas comment Does JavaScript Guarantee Object Property Order?.
properties order in objects is not guaranteed. So, if you need to rely on keyVal order a new step must be done: sorting on Object.keys.
A solution can be based looping on Object.keys and modulus operator in order to group by col or division for a row ordering:
var obj = {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i'};
var resultByCol = [];
var resultByRow = [];
var objKeys = Object.keys(obj).sort(function(a, b) {
return a - b;
});
for (var idx = 0; idx < objKeys.length; idx++) {
var newIdx = idx % 3;
if (resultByCol[newIdx] === undefined) {
resultByCol.push([]);
}
resultByCol[newIdx].push([obj[objKeys[idx]]]);
newIdx = Math.floor(idx / 3);
if (resultByRow[newIdx] === undefined) {
resultByRow.push([]);
}
resultByRow[newIdx].push([obj[objKeys[idx]]]);
}
console.log('Grouped by Col: [');
for (var i = 0; i < resultByCol.length; i++) {
console.log('\t' + JSON.stringify(resultByCol[i]) + (((i + 1) == resultByCol.length) ? '' : ','));
}
console.log(']');
console.log('Grouped by Row: [');
for (i = 0; i < resultByRow.length; i++) {
console.log('\t' + JSON.stringify(resultByRow[i]) + (((i + 1) == resultByRow.length) ? '' : ','));
}
console.log(']');

This can be achieved very quickly and efficiently using keys and a simple for loop to keep your code expedient.
#gaetanoM's solution will work just fine, but for a more performant function you can do the following:
var object = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e', 6:'f', 7:'g', 8:'h', 9:'i'};
var keys = Object.keys(object);
var result = [];
for ( var i=, j=keys.length; i<j; i++){
result[i] = object[keys[i]];
}

Yes. There are a number of ways to do it. Probably the cleanest looking would be to use the reduce() function:
const obj = { 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i' };
const width = 3; // how many in each sub array.
const result = Object.keys(obj).map(key => obj[key]) // ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
.reduce((result, v) => {
if (result[result.length - 1].length === width) {
result.push([v]); // add new row
} else {
result[result.length - 1].push(v); // add to last row
}
return result;
}, [[]]);
console.log(result);
This is a little more verbose then it needs to be, but more understandable.
First, I loop through and map() the object to a normal array.
Then, in the reduce() function, I start it with the first level of nested arrays. Then on each loop, I check the length of the last array in result. If it's full, I add a new array for the next row. Otherwise, I just add the value to the last row.
A more compact version would be:
const obj = { 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i' };
const width = 3;
const result = Object.keys(obj).reduce((r, k) =>
r.concat(
r[r.length - 1].length === width
? [[obj[k]]]
: [r.pop().concat(obj[k])]
), [[]]);
console.log(result);
This example makes more use of .concat() so everything is technically on one line, though obviously it's a good bit harder to read and understand.

Related

How do you merge certain items in a JavaScript array?

Say you have the following array:
const ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
How would you change this array so that all the "b" items get grouped together, until you hit another "a".
So the result of the above array would look like:
['a', 'a', 'bbb', 'a', 'bb', 'a'];
I'm trying to solve a problem with wrapping span tags around words that match a patter in a React app, but this is essentially my problem.
I've been working at it for ages but can't come up with anything I'm happy with.
Any ideas?
Cheers.
Count repeating occurences, then build the result based on that:
const result = [];
let curr = array[0], count = 1;
for(const el of array.slice(1).concat(undefined)) {
if(el !== curr || el !== "b") {
result.push(curr.repeat(count));
curr = el, count = 1;
} else count++;
}
Assuming the elements will always be single letters, you can merge the elements, then match on either bs or non-bs:
ab.join('').match(/(b+|.)/g)
const ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
let output = ab.join('').match(/(b+|.)/g);
console.log(output);
Using Array#reduce you could do something like this.
I'm assuming the first two characters in your solution were a typo.
const data = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
const res = data
.reduce((a,c)=>{
const lastIndex = a.length - 1;
if(a[lastIndex] && a[lastIndex].includes('b') && c === 'b') a[lastIndex] += c;
else a.push(c);
return a;
}, []);
console.log(res);
I don't know how to give an explanation for this but using reduce you can do it like this:
const ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
function merge(arr) {
return arr.reduce((acc,cur, index) => {
if(arr[index - 1] === 'b' && cur !== 'a') {
acc[acc.length - 1] = acc[acc.length - 1] + cur;
return acc;
}
acc.push(cur);
return acc;
},[]);
}
console.log(merge(ab))
Here's what you're after:
var ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
var index = 0;
var groupedArray = [];
var firstOccurence = true;
var groupedString = "";
var grouping = false;
for (var a = 0; a < ab.length; a++) {
if (ab[a] == "a") {
if (grouping) {
grouping = false;
firstOccurence = true;
groupedArray.push(groupedString);
}
groupedArray.push(ab[a]);
} else {
if (firstOccurence) {
groupedString = "";
firstOccurence = false;
}
groupedString += ab[a];
grouping = true;
}
}
console.log(groupedArray);
If you just want to merge b then you could use reduce like this:
If the current item and the previous item are b, then append it to the last accumulator item. Else, push it to the accumulator
const ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a']
const output = ab.reduce((acc, c, i, arr) => {
arr[i-1] === "b" && c === "b"
? acc[acc.length - 1] += c
: acc.push(c)
return acc;
},[])
console.log(output)
You can just map through the ab array and if the current element is a, push it to a new array but if the current element is b, check if the previous element is b or not, and if it is, merge the current element to the previous element else just push the b to the new array.
const ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
let arr = [];
ab.map((e,i) => {
if(i > 0) { // check if element is the first one or not
if(e == "b") {
if(ab[i - 1].indexOf('b') > -1) { // check if prev element is "b" or not
arr[arr.length-1] += e; // merge if prev element is "b"
} else {
arr.push(e);
}
} else {
arr.push(e);
}
} else {
arr.push(e);
}
});
console.log(arr);
N.B. The reduce() method approach and the regex approach shown in the other answers are cleaner and more concise as compared to the map() method approach shown above though.
you can stringify your array then split it with a match of b or more or any other character
const ab = ['a', 'a', 'b', 'b', 'b', 'a', 'b', 'b', 'a'];
const res = ab.join("").match(/(b{1,}|.)/g);
console.log(res)

JavaScript Join Identical Adjacent Elements in an Array

Input:
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e']
Desired output:
['aaa', 'bb', 'ccc', 'd', 'ee']
Is this possible?
Edit: I forgot to mention that my previous attempt (for another example) failed, and I cannot figure out why:
let newArr = []
let last
let current
for (var i = 0; i < arr.length; i ++) {
last = last || isCurrencyArr[i]
current = isCurrencyArr[i]
let str = ''
if (last === current) {
str += arr[i]
} else {
newArr.push(str)
str = ''
}
last = isCurrencyArr[i]
}
Your example has a few hiccups. It redeclares str inside each iteration, therefore it only ever pushes empty strings. Also, it pushes the previous string when it comes across a new item, but it doesn't account for scenarios where the last items are the same, as in your example with the letter e.
If you're joining alike elements together, regardless of position...
Instead, you could use reduce() and spread syntax for object literals to build an object that keeps track of the occurrences of each item.
The object after reduce() looks like this:
{ a: "aaa", b: "bb", c: "ccc", d: "d", e: "ee" }
Once that object is built, all we have to do is create an array from the values using Object.values().
const arr = ['a', 'b', 'a', 'c', 'b', 'a', 'e', 'd', 'c', 'e', 'c'];
let items = arr.reduce((acc,i) => acc[i] ? {...acc, [i]: acc[i]+i } : {...acc, [i]: i }, {});
let result = Object.values(items);
console.log(result);
If you only want to join adjacent alike elements...
The example below uses a slightly similar approach to the above, however this reduce() outputs a string. The logic is similar to your own example: if the previous item is the same, add it to a string. If it is not, separate it and keep going.
The result is something like this: aaa|bb|ccc|d|ee. To turn that into an array, we just need to do split("|").
const arr = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e'];
let result = arr
.reduce((acc,i,idx,a) => (a[idx-1] === i || idx===0) ? acc+i : acc+"|"+i, "")
.split("|");
console.log(result);
This can be a solution to join adjacent elements:
const arr = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e'];
const resp = arr.reduce((a, e) => {
if(a.length === 0) return a.concat(e);
if(e === a[a.length - 1].split('').reverse()[0]) {
a[a.length - 1] = a[a.length - 1].split('').concat(e).join('');
return a;
}
return a.concat(e);
}, [])
console.log(resp);
Something like this should work:
function simplify(arr) {
let current = arr[0];
let final_arr = [];
let accumulated = current;
for (let i = 1; i < arr.length; i += 1) {
if (current === arr[i]) {
accumulated += arr[i];
} else {
final_arr.push(accumulated)
current = arr[i];
accumulated = current;
}
}
final_arr.push(accumulated);
return final_arr;
}
Using Array#reduce, spread syntax, and Map.
const data = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e'];
const res = [...data.reduce((a,c)=>{
return a.set(c, (a.get(c)||"") + c);
}, new Map()).values()];
console.log(res);
Algo for strictly adjacent elements.
const data = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e'];
const res = [];
for(let i = 0; i < data.length; i++){
const c = data[i];
let str = c;
for(let j = i + 1; j < data.length && c === data[j]; j++,i++){
str += c;
}
res.push(str);
}
console.log(res);

Find all the combinations for each element in mutliple arrays

I have the following object
var mapping = {
0: ['A','B','C'],
1: ['D','E','F'],
2: ['G', 'H', 'I'],
---
---
9: ['X','Z']
}
There is a function that references the above object and finds all the possible combinations. For example, we have
function combination(value){}
combination([1,0]); // DA, DB, DC, EA, EB, EC, FA, FB, FC
So in the above invocation the keys at "1" and "0" from the map object will be referenced and all the possible combinations for those two will be returned.
I think the best way to solve this would be to use a recursion, but i just can't seem to wrap my head around this
Not just recursion you can use multiple for loops to achieve this
for (var i = 0 ; i < mapping[index1].length ; i++)
{
for (var j = 0 ; j < mapping[index2].length ; j++)
{
resultArray.push(mapping[i][j]);
}
}
here resultArray is the output array, index1, index2 are the indexes passed
Close enough:
var mapping = {
0: ['A', 'B', 'C'],
1: ['D', 'E', 'F'],
2: ['G', 'H', 'I'],
9: ['X', 'Z']
}
function combine(array, index1, index2) {
var result = array[index1].map(function (el1) {
return array[index2].map(function (el2) {
return [el1, el2].join('');
})
});
return [].concat.apply([], result);
}
function combineAll(array, indices) {
var result = [];
for (var i = 0; i < indices.length - 1; i++) {
var index = indices[i];
var nextIndex = indices[i + 1];
result = result.concat(combine(array, index, nextIndex));
}
return result;
}
var combinations = combineAll(mapping, [1, 0, 9]);
console.log(combinations);
document.write(JSON.stringify(combinations, null, 2));
To find all possible combination we have to iterate over mapping object as well as array corresponding to given key, here i create two functions combination which will iterate over mapping object keys and map which will iterate of array corresponding to each given key:
var mapping = {
0: ['A','B','C'],
1: ['D','E','F'],
2: ['G', 'H', 'I'],
3: ['J', 'K', 'L'],
4: ['M', 'N', 'O']
}
var resultArray = [];
function combination(x){
for(var i=0;i<x.length;i++){
for(var j=i+1;j<x.length;j++){
map(x[i],x[j])
}
}
}
function map(index1,index2){
for (var i in mapping[index1])
{
if(mapping[index1].hasOwnProperty(i)){
for (var j in mapping[index2])
{
if(mapping[index2].hasOwnProperty(j)){
resultArray.push(mapping[index1][i]+''+mapping[index2][j]);
}
}
}
}
}
combination([0,2,1,4])
console.log(resultArray);
You can use recursion in order to solve this problem.
Simply iterate through the indices, and try to add every corresponding item recursively.
I have implemented a working JS function for you:
function combination(o) { // just a wrapper for convenient usage
var current = [];
function step() { // recursive function
if (current.length === o.indices.length) { // combination is ready
o.callback(current); // callback
return; // and leave recursion
}
// current.length is a current position (0, 1, 2, 3 etc.) for which we find a value
// o.indices[o.current.length] is an index of mapping for current position (0, 2, 2, 1 in a demo below)
// o.mapping[o.indices[o.current.length]] is simply a row
o.mapping[o.indices[current.length]].forEach(function(x) {
current.push(x);
step();
current.pop();
});
}
step(); // start recursion
}
You can use it this way:
combination({
mapping: { // your mapping
0: ['A', 'B', 'C'],
1: ['D', 'E', 'F'],
2: ['G', 'H', 'I']
},
indices: [0, 2, 2, 1], // indices may repeat
callback: function(x) { // callback will be called every time we find a combination
document.body.innerHTML += x + "<br/>"; // x is an array
}
});
Here is the working JSFiddle demo.
Following is a solution using recursion.
It does a DFS (Depth First Traversal ) to find all the paths of length corresponding to the input array.
For every dive to the next level, the array gets shortened using slice(1). The original array is not modified and the pattern repeats. When there are no more elements in the array, the path is printed.
I have added a count to see how many combinations are generated. The count should be a product of the lengths of all arrays in the initial input array.
That is for snippet with input array [2,0,3,7] , the product is 3 * 3 * 4 * 3 = 108, i.e 108 combinations.
Essentially picture a tree with the first level nodes with all mapping[2] elements, each of those have mapping[0] children making level 2 of the tree, each level 2 then has mapping[3] elements as children at level 3 and finally mapping[7] would make up the leaf nodes of the tree. This can go to any level based on your input array and your mapping configuration.
The code below does a recursive traversal of the above tree, each time going from root to each leaf node and prints out that path.
var mapping = {
0: ['0A','0B','0C'],
1: ['1A','1B','1C'],
2: ['2A','2B','2C'],
3: ['3A','3B','3C', '3D'],
4: ['4A','4B','4C'],
5: ['5A','5B','5C'],
6: ['6A','6B','6C'],
7: ['7A','7B','7C']
}
var count = 0;
function traverse(arr, comb) {
if(!arr.length) {
console.log(++count + " : " + comb+"\n");
return;
}
for(var j =0; j < mapping[arr[0]].length; j++)
traverse(arr.slice(1), comb + " " + mapping[arr[0]][j]);
}
traverse([2,0,3,7],"");

Basic JavaScript associative array

I have an array of items.
var items = {'A', 'A', 'A', 'B', 'B', 'C'}
I want to output an array that counts how many of each item there is.
So the output should look like:
{
'A': 3,
'B': 2,
'C': 1
}
The biggest reason why it isn't working is that using {} means that you are declaring an object, using [] means you are declaring an array.
Other than that, the code you wrote requires very little modification
var items = ['A', 'A', 'A', 'B', 'B', 'C'];
function count(items) {
var result = [];
var count = 0;
for (var i=0; i<items.length; i++) {
var item = items[i];
if(typeof result[item] === 'undefined') {
//this is the first time we have encountered this key
//so we initialize its count to 0
result[item] = 0;
}
result[item]++;
}
return result;
}
var result = count(items);
for (var key in result) {
alert(key + " : " + result[key]);
}
If you have an array [] instead of an object {} this works:
var items = ['A', 'A', 'A', 'B', 'B', 'C'];
var o = {};
items.forEach(function(element) {
(element in o) ? o[element]++ : o[element] = 1;
});
If you have a real object with keys and values you could use Object.keys() on items to return an array.

Javascript - sort array based on another array

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

Categories

Resources