How to get unique objects from objects array in javascript - 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.

Related

Correctly reorganising JSON to JS array

I have a JSON string that is similar to below:
[
{"id":"112233","region":"UK","city":"London","name":"Company 1"},
{"id":"112244","region":"UK","city":"London","name":"Company 2"},
{"id":"112255","region":"UK","city":"Manchester","name":"Company 3"},
{"id":"112266","region":"UK","city":"Manchester","name":"Company 4"}
]
I am trying to rebuild this into a JS array like this:
[
{
["London"]: [
["112233"] : [{"id":"112233","region":"UK","city":"London","name":"Company 1"}],
["11224"] : [{"id":"112244","region":"UK","city":"London","name":"Company 2"}],
],
["Manchester"]: [
["112255"] : [{"id":"112255","region":"UK","city":"Manchester","name":"Company 3"}],
["112266"] : [{"id":"112266","region":"UK","city":"Manchester","name":"Company 4"}]
]
}
]
Here is the code I am using to do this:
var company = [];
var companies = [];
var cities = [];
// generate citites
for (var i = 0; i < dump.length; i++)
{
// check if city exits
if(!cities.includes(dump[i].city.trim())) {
cities[dump[i].city.trim()] = companies;
}
}
// add companies
for (var i = 0; i < dump.length; i++)
{
company['company_name'] = dump[i].company_name;
company['region'] = dump[i].region;
cities[dump[i].city][dump[i].id] = company;
}
console.log(cities);
Now I get an error stating Cannot set property '112233' of undefined TypeError: Cannot set property '112233' of undefined.
Can someone explain what I'm doing wrong?
The formatting of your desired results is a little strange because you are using [] for what looks like objects with keys. I'm assuming that's a typos and that you really want an object.
Here's a quick easy way to do that with reduce():
let dump = [
{"id":"112233","region":"UK","city":"London","name":"Company 1"},
{"id":"112244","region":"UK","city":"London","name":"Company 2"},
{"id":"112255","region":"UK","city":"Manchester","name":"Company 3"},
{"id":"112266","region":"UK","city":"Manchester","name":"Company 4"}
]
let obj = dump.reduce((obj, item) => {
let city = obj[item.city] || (obj[item.city] = {}) // add city obj to object if not there.
city[item.id] = item // add item.id to city obj
return obj
}, {})
console.log(obj)
EDIT:
The way reduce() works is to start with a value that is passed in the second parameter, here that's an empty object {} that is called obj in the callback, and then iterate through the array (dump). With each iteration we look and see if this obj has a property with the name of the current item in the iteration. If not add it and assign a new object {}. Then with that object in hand, add a property corresponding to item.id and adding the whole item to it.
You could write the entire thing as a for loop, but reduce is pretty succinct — it just takes a while to get used to it.

jQuery compare two arrays objects to have one final array objects

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;

JS: Convert a specific values from an object into an array?

I have an object:
var obj =
[
{
"value": "aep",
"label": "AEP"
},
{
"value": "cap",
"label": "CAP"
},
{
"value": "casl",
"label": "CASL"
} ]
And I want to convert the values of the labels ONLY into an array so that the end result is:
["AEP", "CAP", "CASL"]
How do I only get the label values converted in an array?
First: obj is not an object, it is an array since the parent brackets are [] and not {}. I will, however, keep the name the same. This might have caused you some confusion, e.g.
var object = {};
var array = [];
var arrayOfObjects = [{},{},{}];
var objectOfArrays = {array1: [],array2: [],array3: []};
To loop an array you can use a for loop:
// new array
var newArray = [];
// iterates over each index in the array
for(var i=0; i<obj.length; i++) {
// Access the specific index, then access its `label` property
// Push into `newArray`
newArray.push(obj[i].label);
}
console.log(newArray);
Codepen: http://codepen.io/theblindprophet/pen/RRxVba
Using a for loop
var out = [];
for (var i = 0, len = obj.length; i < len; i++) {
out.push(obj[i].label);
}
console.log(out);
Its simple. You can use map function of javascript array
var obj =
[
{
"value": "aep",
"label": "AEP"
},
{
"value": "cap",
"label": "CAP"
},
{
"value": "casl",
"label": "CASL"
} ]
var arr = obj.map(function(data){return data.value});
This is a functional solution and not the most straightforward one, you may want to refer to #theblindprophet's answer for the imperative approach to this problem.
Pretty easy task to be done in a functional way:
var labels = obj.map(function(inner) { return inner.label });
How does one approach such a problem: You need to think of how to transform the data you have to the data you want. In this case you have an Array of Objects and you want to transform this Array of Objects to an Array of Strings placed inside that Object.
The above code iterates over the Array and returns the value you want for the current element of the Array, building a new Array in the course (map)

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;
}
});

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