jQuery compare two arrays objects to have one final array objects - javascript

Could anyone help on below scenario?
I have two array objects to compare based on model and serial and need to come out with one result only.
Please refer to below sample. Thanks.
ArrayObject1 = [{model:'M1', serial:'S1', file:'F1', other:null},
{model:'M2', serial:'S2', file:'F2', other:null}];
ArrayObject2 = [{model:'M1', serial:'S1', file:null, other:'F3'},
{model:'M3', serial:'S3', file:null, other:'F4'}];
ExpectedResult = [{model:'M1', serial:'S1', file:'F1', other:'F3'},
{model:'M2', serial:'S2', file:'F2', other:null},
{model:'M3', serial:'S3', file:null, other:'F4'}];

I don't think jquery offers an easy method to solve your problem. And this is my solution:
var arr1 = [
{ model: "M1", serial: "S1", file: "F1", other: null },
{ model: "M2", serial: "S2", file: "F2", other: null }
];
var arr2 = [
{ model: "M1", serial: "S1", file: null, other: "F3" },
{ model: "M3", serial: "S3", file: null, other: "F4" }
];
var arr3 = arr1.concat(arr2);
var result = [];
arr3.forEach(function(item1, index){
var arr4 = result.filter(function(item2, index){
return item1.model === item2.model;
});
if (arr4.length === 1) {
for(var prop in item1){
if (item1.hasOwnProperty(prop)) {
arr4[0][prop] = (item1[prop] || arr4[0][prop]);
}
}
}else{
result.push(item1);
}
});
console.log(result);
This only works for the situation when there are atmost 2 models with same model name to merge, because if there are three 'M1' and two of them have none-null 'file', then i don't know which to choose..

var ExpectedResult = [];
//loop through either of the object array. Since they are of same length, it wouldn't matter which one you choose to loop though.
for(var i = 0; i < ArrayObject2.length; i++) {
//check to see if the array element(which are objects) have the same model property
if(ArrayObject2[i].model === ArrayObject1[i].model){
//if they are the same, starting switching the values of the file and other properties in either one of the array
//I choose ArrayObject2, it won't matter which one you decide to use
//this chooses which is truthy between file property of ArrayObject2 at index i and file property of ArrayObject1 at index i and assigns it to the file property of ArrayObject2 at index i
ArrayObject2[i].file = ArrayObject2[i].file || ArrayObject1[i].file;
//this chooses which is truthy between other property of ArrayObject2 at index i and other property of ArrayObject1 at index i and assigns it to the other property of ArrayObject2 at index i
ArrayObject2[i].other = ArrayObject2[i].other || ArrayObject1[i].other;
//push the ArrayObject2 at position i into the ExpectedResult array
ExpectedResult.push(ArrayObject2[i]);
}
//other wise; if the model property differs, just push the ArrayObject1 and ArrayObject2 at index i
else {
ExpectedResult.push(ArrayObject1[i]);
ExpectedResult.push(ArrayObject2[i]);
}
}
ExpectedResult;

Related

How to Insert Key Value Pairs inside Nested Arrays in JavaScript

I need to achieve the same output but as you see the length of the ID's array is zero because I cannot achieve this output using push command, it generates errors like:
push is not a function
Cannot use indexOf for undefined or false
I need to solve this array with a push command and make the output exactly like below but I cannot use the each function because the length is zero.
var RepeaterClass = {
Repeaters: [],
collectRepeaterValues: function (rep_id, cat_id, element_id) {
this.Repeaters[rep_id] = this.Repeaters[rep_id] || [];
this.Repeaters[rep_id][cat_id] = this.Repeaters[rep_id][cat_id] || [];
if (-1 === this.Repeaters[rep_id][cat_id].indexOf(element_id)) {
this.Repeaters[rep_id][cat_id].push(element_id);
}
},
};
Implementing of this code:
ID_1: Array(0)
category: Array(1)
0: "dog"
animals: Array(2)
0: "dog"
1: "cat"
As others have commented it's not entirely clear what you're asking here. This code sort of works if you fix the line var Repeaters =[];
I think the confusion is arising because we create Repeaters as an array, but then I think you must be calling collectRepeaterValues with strings for rep_id and cat_id (e.g. 'ID_1' and 'animals') to get the output you are showing. It should be called with numbers if you want to create arrays. You can't access an array element with a string.
If you call with strings JavaScript is going to create object properties on the array when you do Repeaters[rep_id] = Repeaters[rep_id] || []. That is to say, if we execute the statement Repeaters['ID_1'] = [] in JavaScript it's not doing array assignment even if Repeaters is an array. It will create an object property called ID_1 and makes its value the empty array.
The snippets below show calling the (corrected) object with numbers and with strings and the results.
As an aside, the if statement in collectRepeaterValues is not working.
Now we're back on what the question really is. Do you want arrays, which have to be indexed by numbers of course, or do you want objects with string properties?
// CALLING WITH STRINGS
var RepeaterClass = {
Repeaters: [], // Fixed so it's an object property
collectRepeaterValues: function (rep_id, cat_id, element_id) {
this.Repeaters[rep_id] = this.Repeaters[rep_id] || [];
this.Repeaters[rep_id][cat_id] = this.Repeaters[rep_id][cat_id] || [];
if (-1 === this.Repeaters[rep_id][cat_id].indexOf(element_id)) {
this.Repeaters[rep_id][cat_id].push(element_id);
}
}
}
// What I think you're doing?
RepeaterClass.collectRepeaterValues("ID_1", "category", "dog");
RepeaterClass.collectRepeaterValues("ID_1", "animals", "dog");
RepeaterClass.collectRepeaterValues("ID_1", "animals", "cat");
// At the top level RepeaterClass.Repeaters is an empty array with a 'ID_1' property
// Array length is zero...
console.log(RepeaterClass.Repeaters.length); // 0
// But we have a property ID_1, that is itself an array of zero length with category
// and animals properties that are arrays
console.log(RepeaterClass.Repeaters.ID_1.category[0]); // dog
console.log(RepeaterClass.Repeaters.ID_1.animals[0]); // dog
console.log(RepeaterClass.Repeaters.ID_1.animals[1]); // cat
// Note that this IS the result at the end of the question
// EDIT: You can iterate over the properties with for..in
console.log('Iterating categories on ID_1:');
for (var cat_id in RepeaterClass.Repeaters.ID_1) {
console.log(cat_id);
}
// CALLING WITH NUMBERS
var RepeaterClass = {
Repeaters: [], // Fixed so it's an object property
collectRepeaterValues: function (rep_id, cat_id, element_id) {
this.Repeaters[rep_id] = this.Repeaters[rep_id] || [];
this.Repeaters[rep_id][cat_id] = this.Repeaters[rep_id][cat_id] || [];
if (-1 === this.Repeaters[rep_id][cat_id].indexOf(element_id)) {
this.Repeaters[rep_id][cat_id].push(element_id);
}
}
}
// How this code is meant to be called I think
RepeaterClass.collectRepeaterValues(0, 0, "dog");
RepeaterClass.collectRepeaterValues(0, 1, "dog");
RepeaterClass.collectRepeaterValues(0, 1, "cat");
// At the top level RepeaterClass.Repeaters is now an array structure
console.log(RepeaterClass.Repeaters.length); // 1
console.log(RepeaterClass.Repeaters[0][0][0]); // dog
console.log(RepeaterClass.Repeaters[0][1][0]); // dog
console.log(RepeaterClass.Repeaters[0][1][1]); // cat
The Only Solution I found is by create another array to store the elements inside the repeater then push it in the main Repeaters array outside the funtion
But Still cannot achieve it in the same function.
var RepeaterClass = {
Repeaters: {},
validated: {},
collectRepeaterValues: function( cat_id, element_id ) {
// this.Repeaters[ rep_id ] = this.Repeaters[ rep_id ] || [];
this.validated[ cat_id ] = this.validated[ cat_id ] || [];
if ( -1 === this.validated[ cat_id ].indexOf( element_id ) ) {
this.validated[ cat_id ].push( element_id );
}
}
AnotherFunction: function() {
_.each( REP, function( repDetails, repID ) {
_.each( repDetails, function( value ) {
/* 1. Call the Collector */
collectRepeaterValues( value['cat'], value['id'] );
} );
/* 2. push the validated output inside the main array */
this.Repeaters[ repID ] = this.Repeaters[ repID ] || [];
this.Repeaters[ repID ] = this.validated;
/* Empty for another session */
this.validated = {};
} );
}
}

How to get unique objects from objects array in javascript

I have an array of objects that looks like the image below. Is there a way by which I can have an array that contains unique objects with respect to id ? We can see below that the id are same at index [0] and index [2].
Is there a way that I can get an array containing objects with unique id and the first object from the last index is added to the unique array rather than the first object. In this case, Object at index[2] should be added instead of object at index[0]:
To get an array of "unique" objects(with last index within the list) for your particular case use the following approach (Array.forEach, Array.map and Object.keys functions):
// exemplary array of objects (id 'WAew111' occurs twice)
var arr = [{id: 'WAew111', text: "first"}, {id: 'WAew222', text: "b"}, {id: 'WAew111', text: "last"}, {id: 'WAew33', text: "c"}],
obj = {}, new_arr = [];
// in the end the last unique object will be considered
arr.forEach(function(v){
obj[v['id']] = v;
});
new_arr = Object.keys(obj).map(function(id) { return obj[id]; });
console.log(JSON.stringify(new_arr, 0, 4));
The output:
[
{
"id": "WAew111",
"text": "last"
},
{
"id": "WAew222",
"text": "b"
},
{
"id": "WAew33",
"text": "c"
}
]
The best way to do this is to modify your data structure into an object itself where each key is one of the IDs:
{
"WadWA7WA6WAaWAdWA...": {
"text": "birla"
},
"WadWA...": {
"test": "ab"
}
}
and so forth. If the data comes from a source formatted that way, you can always map the array of results to this format.
You could create a hash using the id as the key and keeping the value as the entire object:
var myHash = new Object();
var i;
for(i = 0; i < yourArray.length; i++) {
var yourObjId = yourArray[i][id];
myHash[yourObjId] = yourArray[i];
}
You would be left with a hash myHash containing objects with unique id's (and only the last object of duplicates would be stored)
Try this: just add to a new object using id as the key
var arr = [{id:'123', text: 'a'}, {id:'234', text: 'b'}, {id:'123', text: 'c'}];
var map = new Object();
for(var i in arr){ map[arr[i].id] = arr[i]; }
var newArr = [];
for(var i in map){ newArr.push(map[i]); }
newArr shall contain the 2nd and 3rd object.

What is the most elegant way of partly copying object arrays in JavaScript

I have two arrays of objects. arrayOne contain items type of myObject1:
var myObject1 = {
Id: 1, //key
params: { weight: 52, price: 100 },
name: "",
role: ""
};
arrayTwo contained items type of myObject2:
var myObject2 = {
Id: 1, //key
name: "real name",
role: "real role"
};
I want to copy all names and roles from arrayTwo to arrayOne.
id is the key, both arrays contains myObjects with that is mached by 'id`.
If the two arrays are guaranteed to be congruent, then with the use of jQuery.extend(), the code is trivial :
$.each(arrayOne, function(i, obj) {
$.extend(obj, arrayTwo[i]);
});
A solution that runs in linear time.
var arrayOne; // Array containing objects of type myObject1
var arrayTwo; // Array containing objects of type myObject2
var tempObj = {};
// Transform arrayOne to help achieve a better performing code
arrayOne.forEach(function(obj){
tempObj[obj.id] = obj;
});
// Runs on linear time O(arrayTwo.length)
arrayTwo.forEach(function(obj){
// Note, since I'm not adding any thing to the arrayTwo
// I can modify it in this scope
var match = tempObj[obj.id];
if(match){
// If a match is found
obj.name = match.name;
obj.role = match.role;
}
});

Array within object returning length of 0, even though there are elements present

I am trying to implement a Trie in Javascript, which is easy enough but I seem to have hit a road block with my object.
The nodes are structured as follows:
var node = {
children: []
}
Children is an array of nodes that is mapped by a letter in a string. So the string "Test" would look like this:
root = {
children: [
't' => {
children: [
'e' => {
children: [
's' => {
children: [
't' => {
children: []
}
]
}
]
}
]
}
]
};
So each children array should have a length of 1, but if do something like alert(this._root.children.length); I get zero. Any thoughts on why this is happening?
Here is the rest of my implementation:
function Trie() {
this._root = {
children: []
};
}
Trie.prototype = {
//restore constructor
constructor: Trie,
add: function (str){
var curr = this._root,
prev,
currchar;
// For each character in the string
for(var i = 0, j = str.length; i < j; i++) {
// Insert only lowercase letters for efficiency
currchar = str.toLowerCase().charAt(i);
prev = curr;
curr = prev.children[currchar];
// Traverse until we hit a non-existant node
if(typeof(curr) == "undefined") {
// Make a new node
prev.children[currchar] = {
children: []
};
curr = prev.children[currchar];
}
}
}
You are adding properties to the array instance object, not elements to the array. The length property only includes array elements, not properties on the array instance object.
var a = [23, 42];
console.log(a.length); // 2
a['foo'] = 'bar';
console.log(a.length); // 2
a[2] = 1337;
console.log(a.length); // 3
EDITED:
You could instead structure the nodes like this:
var node = {
children: {},
length: function () {
var i = 0;
var k;
for (k in this.children) {
if (this.children.hasOwnProperty(k)) {
i++;
}
}
return i;
}
};
This is inefficient, of course. You should instead define a Node class with the length method on its prototype. Alternatively, define an add method that updates the length property.
I think that the problem is that you use a javasrcipt array as an associative array (as found in other languages). In javascript "associative" arrays are objects that don't have a length property. Normal arrays have numeric indices.
Irrelevant to the question but you might find this useful.
Maybe you want
str.toLowerCase().charCodeAt(i)
instead of
str.toLowerCase().charAt(i)
If str is "f1", the properties you're adding to the children array are "f" and "1" which should cause an array with property named f and length 0, and another child array with length 2 and property 1.
To get only numeric properties, you should make sure your property names are valid array indices -- positive integers representable in 31 bits.
By using charCodeAt instead of charCode, you would get the property names 102 and 49 instead of "f" and 1.

Group javascript items by one property

My question is related to this question. You will have to first read it.
var ids = "1*2*3";
var Name ="John*Brain*Andy";
var Code ="A12*B22*B22";
Now that I have an array of javascript objects. I want to group my objects based on CODE. So there can be duplicate codes in that code string.
As per the above changed strings, I have same code for Brain and Andy. So, now I want two arrays. In one there will be only one object containing details of only John and in the other object there will be two objects containing details of Brain and Andy.
Just for example I've taken 3 items. In actual there can be many and also there can be many set of distinct codes.
UPDATE
I needed the structure like the one built in groupMap object by the #Pointy. But I will use #patrick's code to achieve that structure. Many thanks to both of them.
It is a little hard to tell the exact resulting structure that you want.
This code:
// Split values into arrays
Code = Code.split('*');
Name = Name.split('*');
ids = ids.split('*');
// cache the length of one and create the result object
var length = Code.length;
var result = {};
// Iterate over each array item
// If we come across a new code,
// add it to result with an empty array
for(var i = 0; i < length; i++) {
if(Code[i] in result == false) {
result[ Code[i] ] = [];
}
// Push a new object into the Code at "i" with the Name and ID at "i"
result[ Code[i] ].push({ name:Name[i], id:ids[i] });
}
Will produce this structure:
// Resulting object
{
// A12 has array with one object
A12: [ {id: "1", name: "John"} ],
// B22 has array with two objects
B22: [ {id: "2", name: "Brain"},
{id: "3", name: "Andy"}
]
}
Split the strings on "*" so that you have 3 arrays.
Build objects from like-indexed elements of each array.
While building those objects, collect a second object that contains arrays for each "Code" value.
Code:
function toGroups(ids, names, codes) {
ids = ids.split('*');
names = names.split('*');
codes = codes.split('*');
if (ids.length !== names.length || ids.length !== codes.length)
throw "Invalid strings";
var objects = [], groupMap = {};
for (var i = 0; i < ids.length; ++i) {
var o = { id: ids[i], name: names[i], code: code[i] };
objects.push(o);
if (groupMap[o.code]) {
groupMap[o.code].push(o);
else
groupMap[o.code] = [o];
}
return { objects: objects, groupMap: groupMap };
}
The "two arrays" you say you want will be in the "groupMap" property of the object returned by that function.

Categories