Sort a three dimensional array in Javascript - javascript

Consider this Array
var LIST =[];
LIST['C']=[];
LIST['B']=[];
LIST['C']['cc']=[];
LIST['B']['bb']=[];
LIST['C']['cc'].push('cc0');
LIST['C']['cc'].push('cc1');
LIST['C']['cc'].push('cc2');
LIST['B']['bb'].push('bb0');
LIST['B']['bb'].push('bb1');
LIST['B']['bb'].push('bb2');
I can loop through this array like
for(var i in LIST){
console.log(i)//C,B
var level1=LIST[i];
for(var j in level1){
console.log(j)//cc,bb
// etc...
}
}
Fine.. I have few basic questions.
1.How to sort the array in each level?
One level can be sort by .sort(fn) method . How can i pass to inner levels?
2.Why the indexOf method does not works to find the elements in first two levels?
If it's because of the a non string parameter .. how can i search an array items in array if the item is not string?
3.How for(var i in LIST) works ?
I just need a basic understanding of indexing and looping through array ..
Thanks ..

LIST is NOT a three dimensional array in Javascript, it is just an array.
//declare an array which names LIST.
var LIST = [];
//set a property named 'C' of the LIST to be an array.
LIST['C']=[];
//set a property named 'B' of the LIST to be an array.
LIST['B']=[];
//set a property named 'cc' of the 'LIST.C'(which is an array object)
LIST['C']['cc']=[];
//set a property named 'bb' of the 'LIST.B'(which is an array object)
LIST['B']['bb']=[];
The fact is you only need to let the last level to be an array, see my example code below.
function iterateOrderd(obj) {
if (obj instanceof Array) {
obj.sort();
for (var j = 0, l=obj.length; j < l; j++) {
console.log(obj[j]);
}
} else {
var sortable = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
sortable.push(i);
}
}
sortable.sort();
for (var j = 0, l=sortable.length; j < l; j++) {
console.log(sortable[j]);
iterateOrderd(obj[sortable[j]]);
}
}
}
var LIST = {};
LIST['C'] = {};
LIST['B'] = {};
LIST['C']['cc']=[];
LIST['B']['bb']=[];
LIST['C']['cc'].push('cc0');
LIST['C']['cc'].push('cc1');
LIST['C']['cc'].push('cc2');
LIST['B']['bb'].push('bb0');
LIST['B']['bb'].push('bb1');
LIST['B']['bb'].push('bb2');
iterateOrderd(LIST);

You need to know that Array inherits from Object.
In JavaScript, any Object instance is an associative array(!), so acts like an Array in PHP. For example:
var o = {}; // or new Object();
o['foo'] = 'bar';
o[0] = 'baz';
for (i in o) { console.log(i, o[i]); }
Sorting an Object does not make much sense. indexOf would kinda work in theory, but is not implemented.
Arrays are ordered lists. Array instances have push(), length, indexOf(), sort() etc., but those only work for numerical indexes. But again, Array inherits from Object, so any array can also contain non-numerical index entries:
var a = []; // or new Array();
a[0] = 'foo'; // a.length is now 1
a.push('baz'); // a[1] === 'baz'
a.qux = 1; // will not affect a.length
a.sort(); // will not affect a.qux
for (i in a) { console.log(i, a[i]); }
I recommend playing around with arrays and objects, and you'll soon get the point.

What is your sorting criteria ? I mean how will you say array firstArray comes before secondArray?
regarding the for (counter in myArray), counter will take values of an array element in every iteration.
for (counter in [0,1,5]), counter will have values 0, 1 and 5 in the 3 iterations.
In your case, i will have values LIST['B'] and LIST['C'] in the two iterations and j will have values LIST['B']['bb'], LIST['B']['cc'], LIST['C']['bb'] and LIST['C']['cc'].
Both i and j will be arrays.

Related

Dynamically created Array always filled with variables

Why is the logged Array always filled with data? Shouldnt it be an array with only one then two then three arrays in it?
var theArray=[];
function insertValues(species,quantity){
var w = window;
w[species]= [];
for(let i =0; i<quantity;i++){
w[species].push({
species:species,
randomValue:Math.random()*10
})
// console.log(theArray);
}
theArray.push(w[species]);
}
var listOfSpecies =[{animal:"Fish",amount:5},{animal:"Shark",amount:5},{animal:"Algae",amount:5}];
for(let i = 0; i<listOfSpecies.length; i++){
console.log(theArray);
insertValues(listOfSpecies[i].animal,listOfSpecies[i].amount);
}
Woah! Firstly, don't assign to window! (unexpected things will almost definitely occur).
Also, JavaScript objects (yes an array is an object, typeof [] === "object" // true) are passed by reference, not by value.
When you add to theArray, a new reference is created. When you go to log it to the console, it shows an empty array at first, but it has actually logged a reference to theArray, therefore, when you go to inspect the contents, it shows an array filled with values;
Even try the example below, the same thing occurs (albeit much simpler to follow)
var arr = [];
for (var idx = 0; idx < 3; idx++) {
console.log(arr);
arr[idx] = idx;
}
to prevent this, you would need to copy the array, like so:
var newArray = Object.assign([], theArray);
Object.assign copies the values of the array (or object), returning a new array (again, or object), but does not create a reference back to the original array or object.

Get object out of multi dimensional array

I have three arrays filled with objects in JavaScript that I've put into a multi-dimensional array in order to get all possible combinations of all three objects to create a set of 'rules'. Then later in the code I want to be able to pull out the properties of these objects, but when I attempt to all I seem to be able to get is the string "[object]" and not the actual object itself.
This is how the array is put together:
var allArrays = [settings.serviceLevels, settings.serviceDays, settings.services];
function allPossibleCases(arr) {
if (arr.length === 1) {
return arr[0];
} else {
var result = [];
var allCasesOfRest = allPossibleCases(arr.slice(1));
for (var i = 0; i < allCasesOfRest.length; i++) {
for (var j = 0; j < arr[0].length; j++) {
result.push(arr[0][j] + allCasesOfRest[i]);
}
}
return result;
}
}
var uncheckedRules = allPossibleCases(allArrays);
I need to be able to get the properties out of settings.serviceLevels, settings.serviceDays and settings.services - I can find questions that do this with regular arrays but not with objects - is this even possible or have I taken it to a level where I've lost the properties?
Not sure I understood what you wanted. But here's a recursive function that will store in an array the properties of objects contained in another array :
function listProps(object, result) {
// for each property of the object :
for (objectProperty in object) {
// if it's an object, recursive call :
if (typeof object[objectProperty] === 'object') {
listProps(object[objectProperty], result);
} else { // otherwise, push it into the result array :
result.push(object[objectProperty]);
}
}
}
var allArrays = [settings.serviceLevels, settings.serviceDays, settings.services];
var result = [];
listProps(allArrays, result);
The result array should list every properties from the three objects settings.serviceLevels, settings.serviceDays, settings.services and their children (if they contain any object themselves).

Copying array onto the "this" variable (creating an Array-like object)

Is there a better way to copy an array onto the this variable
function obj(arr) {
for (var i=0, l=arr.length; i<l; ++i) {
this[i] = arr[i];
}
this.length = arr.length;
}
var o = new obj([1,2,3,4]);
console.log(o[0]); // Outputs 1
Is there any other way to do it, instead of iterating over the whole arr ?
You can use Array#push this way:
function obj(arr) {
Array.prototype.push.apply(this, arr);
}
This will treat this like an array, adding all the elements from arr and setting length correctly. See also Function#apply.
But of course there is still an internal loop. You cannot copy / move a collection values to another collection without iterating over it (unless, I guess, the collections use structural sharing)
You could do it like this:
function obj() {
return this;
}
var o = obj.apply([1,2,3,4]);
console.log(o[0]); // Outputs 1

How To Create Dynamic Arrays Varaibles in Javascript

Can you please let me know if it is possible to create dynamically sets of arrays in JS? I tried some thing like this but didn't work
for (i = 0; i < 3; i++) {
var item[i] = [];
}
item1.push(1);
console.log(item1);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
You're almost there. Assuming you're trying to create a two dimensional array (an array of arrays), you just have to declare the top level array and then reference the first level array with [x] array syntax like this:
var items = [];
for (i = 0; i < 3; i++) {
items[i] = [];
}
// Here items is an array of arrays where each first level array entry
// is an empty array. You can then put things into those empty arrays
// You can reference the first level array here
items[1].push(1);
items[1].push(2);
console.log(items[1]); // [1,2]

Find duplicate object values in an array and merge them - JAVASCRIPT

I have an array of objects which contain certain duplicate properties: Following is the array sample:
var jsonData = [{x:12, machine1: 7}, {x:15, machine2:7},{x:12, machine2: 8}];
So what i need is to merge the objects with same values of x like the following array:
var jsonData = [{x:12, machine1:7, machine2:8}, {x:15, machine2:7}]
I like the lodash library.
https://lodash.com/docs#groupBy
_.groupBy(jsonData, 'x') produces:
12: [ {x=12, machine1=7}, {x=12, machine2=8} ],
15: [ {x=15, machine2=7} ]
your desired result is achieved like this:
var jsonData = [{x:12, machine1: 7}, {x:15, machine2:7},{x:12, machine2: 8}];
var groupedByX = _.groupBy(jsonData, 'x');
var result = [];
_.forEach(groupedByX, function(value, key){
var obj = {};
for(var i=0; i<value.length; i++) {
_.defaults(obj, value[i]);
}
result.push(obj);
});
I'm not sure if you're looking for pure JavaScript, but if you are, here's one solution. It's a bit heavy on nesting, but it gets the job done.
// Loop through all objects in the array
for (var i = 0; i < jsonData.length; i++) {
// Loop through all of the objects beyond i
// Don't increment automatically; we will do this later
for (var j = i+1; j < jsonData.length; ) {
// Check if our x values are a match
if (jsonData[i].x == jsonData[j].x) {
// Loop through all of the keys in our matching object
for (var key in jsonData[j]) {
// Ensure the key actually belongs to the object
// This is to avoid any prototype inheritance problems
if (jsonData[j].hasOwnProperty(key)) {
// Copy over the values to the first object
// Note this will overwrite any values if the key already exists!
jsonData[i][key] = jsonData[j][key];
}
}
// After copying the matching object, delete it from the array
// By deleting this object, the "next" object in the array moves back one
// Therefore it will be what j is prior to being incremented
// This is why we don't automatically increment
jsonData.splice(j, 1);
} else {
// If there's no match, increment to the next object to check
j++;
}
}
}
Note there is no defensive code in this sample; you probably want to add a few checks to make sure the data you have is formatted correctly before passing it along.
Also keep in mind that you might have to decide how to handle instances where two keys overlap but do not match (e.g. two objects both having machine1, but one with the value of 5 and the other with the value of 9). As is, whatever object comes later in the array will take precedence.
const mergeUnique = (list, $M = new Map(), id) => {
list.map(e => $M.has(e[id]) ? $M.set(e[id], { ...e, ...$M.get(e[id]) }) : $M.set(e[id], e));
return Array.from($M.values());
};
id would be x in your case
i created a jsperf with email as identifier: https://jsperf.com/mergeobjectswithmap/
it's a lot faster :)

Categories