I have several objects in an array which looks like this:
var objectArray = [
abc: {id: "qq09qed0000", status: "running"},
def: {id: "qq09qed0001", status: "paused"},
...
xyz: {id: "qq09qed9999", status: "paused"}
];
EDIT: I am not sure, how it is represented in memory, the objectArray is created by doing array.push(object); several hundred times in a loop. The above is just an example to show you what the objects look like, they are truncated and in reality have lots more fields. Please stop telling me that the array is formatted wrong, it is, I am aware, it is just an example. The main thing to consider is how to go from an array of objects to an array of strings.
Edit2: Perhaps it looks like this in memory:
var objectArray = [
{id: "qq09qed0000", status: "running"},
{id: "qq09qed0001", status: "paused"},
...
{id: "qq09qed9999", status: "paused"}
];
If I wanted an ordered array of just the ids (they are non sequential) of all of these elements, what would be the best way to extract them?
I have attempted a foreach loop,
for(var obj in objectArray ) {
dataArray.push(objectArray[obj].getid());
}
But I am told this is not guarranteed to keep the ordering intact.
You can use maybe arr.sort() function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
function sortById (a,b)
{
if (a.id < b.id) return -1
if (a.id > b.id) return 1;
return 0;
}
objectArray.sort (sortById);
Your objectArray is an object, not an array, and as such, has no obvious / defined ordering.
What order the elements are in, depends on the JavaScipt implementation of the browser it's running in.
For that reason, there is no way to "keep the ordering intact.", since there is no set ordering in the first place.
Now that you've edite the question, the objectArray isn't valid JavaScript syntax.
Arrays can't have key:value pairs like this:
var objectArray = [
abc: {id: "qq09qed0000", status: "running"},
From what I gathered from your question, this should work:
data = data2.map(function(e){return e.id;});
This should return an array with only id values, in the same order as in data2.
If you push all the ids in an array first, then sort them after, the fact that the 'for' function does not keep the ordering won't matter
Push all the ids in a new array
var objectArray = {
abc: {id: "qq09qed0000", status: "running"},
def: {id: "qq09qed0001", status: "paused"},
...
xyz: {id: "qq09qed9999", status: "paused"}
};
var idArray = [];
for(var item in objectArray){
idArray.push(item.id);
};
This will produce an array looking like this:
idsArray = ["qq09qed0000","qq09qed0001", ..., "qq09qed9999"]
Next, sort the array using the array sort method
idsArray.sort();
OR
idsArray.sort(function(a,b){
return a - b;
});
This will sort them in alphanumeric order by default. You can also reverse the order using:
idsArray.sort(function(a,b){
return b - a;
});
Namespace.pluck = function(obj, prop)
{
var isFunction = Namespace.isFunction(prop);
return Namespace.map(obj, function(key, element)
{
return isFunction ? prop(element) : element[prop];
});
};
var ids = Namespace.pluck(objectArray, 'id').sort();
Array.prototype.sort() will give you a lexicographical sort, and not a natural sort. 10 will come after 1 but before 2
Related
Let's say I've got the following array of objects in JavaScript:
const requests = [
{
id: 1,
person: {
id: 1
}
},
{
id: 2,
person: {
id: 1
}
},
{
id: 3,
person: {
id: 2
}
},
{
id: 4,
person: {
id: 3
}
},
{
id: 5,
person: {
id: 2
}
}
]
And what I've written below will go over each item in the array, and then create a new array containing just the person object.
const requestsPeopleIds = []
for (const request of requests) {
requestsPeopleIds.push(request.person.id)
}
I then take that new array and create another new array using Set to remove the duplicate ids:
const uniquePeopleIds = Array.from(new Set(requestsPeopleIds))
The final result is as I'd expect:
console.log(uniquePeopleIds) // [1, 2, 3]
where these are the unique ids of the people who made a request. So out of the 5 requests, these were made by 3 people.
There must be a more efficient way of doing this, so I'm reaching out to you stack overflow JS gurus.
Thanks in advance.
I think you got the basics. Here's a way to tighten the code:
var ids = new Set;
requests.forEach(i => ids.add(i.person.id));
You could also do this with map method and spread syntax ....
const requests = [{"id":1,"person":{"id":1}},{"id":2,"person":{"id":1}},{"id":3,"person":{"id":2}},{"id":4,"person":{"id":3}},{"id":5,"person":{"id":2}}]
const result = [...new Set(requests.map(({ person: { id }}) => id))]
console.log(result)
You can do it by making an object by the person's id as a key and get the keys of the object.
const requests = [{"id":1,"person":{"id":1}},{"id":2,"person":{"id":1}},{"id":3,"person":{"id":2}},{"id":4,"person":{"id":3}},{"id":5,"person":{"id":2}}]
// Take an empty object
const uniques = {};
// Iterate through the requests array and make person's id as a
// key of the object and put any value at this index (here I put 1).
requests.forEach(request => (uniques[request.person.id] = 1));
// Finally get the keys of the unique object.
console.log(Object.keys(uniques));
I've done some research and have inferred some interesting facts:
It looks like when we have very various data and larger array, then Set collection shows not best results. Set is very optimized collection, however, in my view, it should always check whether element is already added into Set. And this checking will take O(n) complexity. But we can use simple JavaScript object. Checking whether object contains key is O(1). So object will have huge advantage over Set.
foreach arrow function is very convenient, however, simple for loop is faster.
Adding console.log makes Set the most fastest solution, however, without console.log, the most fastest solution is combination of for loop and object.
So the most performant code without console.log() looks like this:
const hashMap = {};
const uniques = [];
for (let index = 0; index < requests.length; index++) {
if (!hashMap.hasOwnProperty(requests[index].person.id)){
hashMap[requests[index].person.id] = 1;
uniques.push(requests[index].person.id);
}
}
However, the most performant code with console.log() looks like this(I cannot understand the reason why it happens. It would be really great to know why it happens):
var ids = new Set;
requests.forEach(i => ids.add(i.person.id));
console.log(ids)
Tests:
with console.log
without console.log
I was trying one simple piece of code in which an array of objects are present and each object is having another array of products(with duplicate values).
I wanted to combine all the products array together without any duplicates.
Already reached half of iteration process but not able to remove duplicates, is there any way to iterate the values (as it is itself having key value as object 1 and its data..)
please suggest any other optimized way if possible. I'm new to JavaScript so pardon any silly mistakes made
Thanks in advance.
You can do it using concat, Set and Array.from:
const object1 = { products: ['1', '2', '3'] }
const object2 = { products: ['1', '2', '3', '4'] }
const object3 = { products: ['5'] }
// Merge all the products in one Array
const products = object1.products
.concat(object2.products)
.concat(object3.products);
// Create a Set, with the unique products
const set = new Set(products);
// Convert the Set to an Array
const uniqueProducts = Array.from(set);
console.log(uniqueProducts)
To remove duplicates you can use Set, it keeps all items unique, then you can cast it to Array.
Array.from(new Set(array))
there are many ways to achieve this:
you can use filter to remove duplicate elements:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
by reading in value, its index and array in filter function
a quick search link: https://codeburst.io/javascript-array-distinct-5edc93501dc4
you can always write a method for merge which would be good in terms of error handling, corner case checks, so that above action dont result into error,
example:
function MergeUniqueProductFromDictToArry(fromDict, productKey, toArray) {
//check if for the array in which we need to merge
if(!toArray) {
toArray = [];
}
//check for validity
if(!fromDict || !productKey || !fromDict[productKey] || fromDict[productKey].length == 0) {
return toArray;
}
for(var ix in fromDict[productKey]) {
//check if product already exist
if(toArray.indexOf(fromDict[productKey][ix]) === -1) {
toArray.push(fromDict[productKey][ix]);
}
}
return toArray;
}
var object1 = {products: ["p1", "p2", "p1"]};
var object2 = {products: ["p3", "p2"]};
var object3 = {products: ["p4", "p2"]};
var uniqueProducts = MergeUniqueProductFromDictToArry(object1, "products", null);
uniqueProducts = MergeUniqueProductFromDictToArry(object2, "products", uniqueProducts);
uniqueProducts = MergeUniqueProductFromDictToArry(object3, "products", uniqueProducts);
console.log(uniqueProducts);
First of all i check a lot of post, like this:
Finding matches between multiple JavaScript Arrays
How to merge two arrays in Javascript and de-duplicate items
Unique values in an array
All these works fine but only with arrays that contain integers or strings, i need that works for whatever you want.
i have two arrays, and want to storage in a new array the unique elements, and in other array the common elements.
These elements could be; variables, arrays, strings, hash (objects) functions, integers, float numbers or boolean
And probably never gonna be a duplicate value inside of the arrays.
Would be awesome with plain JS
And i don't care about IE (but would be nice for others i guess), so if there is a new ES6 way, i gonna love it , i care more about performance :)
// Some values that gonna be inside the array1 & array2
function random(){};
var a = 5,
b = {};
// The Arrays
var array1 = [0,1,2,3, "HeLLo", "hello", 55.32, 55.550, {key: "value", keyWithArray: [1,2,3]}, random, a, b];
var array2 = [2,3, "hello", "Hello", 55.32, 55.551, {key: "value", keyWithArray: [1,2,3]}, b];
// The Unique Array should be all the elements that array1 have and array2 haven't
var uniqueArray = [0, 1, "HeLLo", 55.550, random, a];
// The commonArray should the common elements in both arrays (array1 and array2)
var commonArray = [2,3, "hello", 55.32, {key: "value", keyWithArray: [1,2,3]}, b]
// I try something like this but doesn't work
var uniqueArray = array1.filter(function(val) { return array2.indexOf(val) == -1; });
console.log(uniqueArray);
From what I understood you basically want to perform some set operations on your two arrays. My suggestion is to first build a more appropriate data structure from your two arrays, because to do something like get the intersection of both you would have to do an O(n²) algorithm.
Something like this should do it:
// convert a plain array that has values of mixed types to and object
// where the keys are the values in plain form in case of strings, scalars or functions, or serialized objects in
// case of objects and arrays, and where the values are the unaltered values of the array.
var _toObject = function(arr) {
var obj = {};
for (var i=0 ; i<arr.length ; i++) {
var el = arr[i];
var type = typeof el;
if (type !== 'object') { // scalars, strings and functions can be used as keys to an array
obj[el] = el;
}
else { // objects and arrays have to be serialized in order to be used as keys
obj[JSON.stringify(el)] = el;
}
};
return obj;
};
var objArray1 = _toObject(array1);
var objArray2 = _toObject(array2);
var uniqueArray = [];
var commonArray = [];
for (var i in objArray1) {
if (i in objArray2) {
commonArray.push(objArray1[i]); // push the common elements
delete objArray2[i]; // delete so in the end objArray2 will only have unique elements
}
else {
uniqueArray.push(objArray1[i]); // push unique element from objArray1
}
}
for (var i in objArray2) { // now objArray2 has only unique values, just append then to uniqueArray
uniqueArray.push(objArray2[i])
}
console.log('Unique array', uniqueArray);
console.log('Common array', commonArray);
this should give you the desired result:
bash-4.2$ node test.js
Unique array [ 0, 1, 5, 'HeLLo', 55.55, [Function: random], 'Hello', 55.551 ]
Common array [ 2, 3, 'hello', 55.32, { key: 'value', keyWithArray: [1, 2, 3 ] }, {}]
THis is going to sound like a stupid question but here it goes. I have a js array formatted like so
var locationID = [
{ ID: "ID1", location: "location1" },
{ ID: "ID2", location: "location2" },
{ ID: "ID3", location: "location3" },
];
I am trying to loop through the array
for(i = 0; i < locationID.length;i++){
var object = locationID[i];
}
I want to get both elements from the inner array so the ID and location. would I do this by object[0] or object["ID"] for example.
Also is there a more efficient way to do what I need to do like a for each loop or something along those lines.
Use object.ID or object['ID'].
Objects {} in JavaScript are associative, or named arrays. (Also known as a map in many languages. They are indexed by strings (in this case).
Arrays [], are indexed by integral numbers, starting from 0 and counting up to n-1, where n is the length of the array.
If you want to programmatically go through all the (key, value) pairs in each object, you can use this method.
Quotations (String Literals)
To reiterate my comment below about single and double quotes:
If you're talking about inside the [], no [,they're not important]. JavaScript treats single
quotes and double quotes pretty much the same. Both of them denote
string literals. Interestingly, you can use single quotes inside
double quotes or vice-versa: "I wanted to say 'Hello world!'" would be
a (single) valid string, but so would 'But I accidentally said "Goodbye".
This is an optimized loop based from the book of Nicholas Zackas (YAHOO performance chief). I am performing a cached array length to prevent re-evaluation of array length on every iteration of the loop. Please check jsperf.com. Also, native loop is always faster than method based loops jQuery.each and Array.prototype.forEach. This is also supported on browsers below ie8
var currentItem,
locationInfo = [
{ ID: "ID1", location: "location1" },
{ ID: "ID2", location: "location2" },
{ ID: "ID3", location: "location3" },
];
for (var i = 0, len = locationInfo.length; i < len; i++) {
currentItem = locationInfo[i];
console.log(currentItem.ID);//I prefer this because it shrinks down the size of the js file
console.log(currentItem["ID"]);
}
what you have already will return each of the objects in the JSON as you run the loop. What you need is something like
for(i = 0; i < locationID.length;i++){
var object = {locationID[i].ID, locationID[i].location};
}
Remember properties of objects are accessed by their keys since they are key-value pairs.
For loops are going to be your best bet as far as speed, here's how you'd do it with forEach (IE 9+)
locationID.forEach(function(location, i){
console.log(location['ID'])
console.log(location['location'])
});
jQuery make's it a little easier but runs slower
$.each(array, function(i, item){
});
http://jsperf.com/for-vs-foreach/75
Also here a useful link: For-each over an array in JavaScript?
You can use the forEach method, which make your code more cleaner.
See forEach
locationID.forEach(function(elm){
//Here, elm is my current object
var data = elm;
console.log(data.ID):
console.log(data.location);
});
EDIT :
Then for your second question, you should filter and map methods.
function findNamebyID(id){
//Filter by id and map the data to location
return locationID.filter(function(elm){
return elm.ID === id;
}).map(function(elm){
return elm.location;
})
}
Something as:
var location = locationID.reduce(function(ob, cur) {
ob[cur.ID] = cur.location;
return ob;
}, {});
The result you get is:
Object {ID1: "location1", ID2: "location2", ID3: "location3"}
Meaning you can do:
location.ID1 // location1
location.ID2 // location2
...
an alternative to your loop, would be to use the JavaScript for (.. in ..) since you aren't really using the iterator; it just adds fluff
for(i = 0; i < locationID.length;i++){
var object = locationID[i];
}
could be written as:
for (item in locationID) {
var object = item;
}
At the moment I have this object:
obj = [object{id: 1, name: test, parentID: 3}, object{id:1, name: another, parentID: 5}, object{id:2, name:something, parentID: 1}].
Ultimately I want an object structured in a different manner.
So that it is object, but if my identifier is 1, it has a collection of names (in this case test, and another). If it is 2, it only shows 'something'.
I can't work out how this should look, probably like so?
obj = [[1,test], [1,another], [2,something]] right?
So that if I call obj[1] I get a multiples back (test, another etc).
Can someone help? I've been fiddling with this for an hour now, I just don't understand.
I built the original object like this:
var obj = Array();
//loop here
var obj = {
id: id,
name: name,
parentID: parentID
};
obj.push(obj);
What did I do wrong? How can I fix this? This got me my object within objects thing, but really I want id's and names within id's and names. My ultimate goal is to iterate through this. So that I only get out the names of anything of a like ID, that way I can use this to populate an array or count
Thus:
if(obj[id] == 1){
//put the name in the new array
}
is my ultimate goal. But I've gotten a bit lost with the initial object creation so now it is a big mess.
Try:
var obj = [{id: 1, name: "Foo"}, {id: 2, name: "Fee"}, {id: 3, name: "Fii"}];
var result = [], item, i = 0;
while(item = obj[i++]){
for(key in item){
if(key === "id") continue; //remove this line if you want to keep the ID also in the array
!result[i] && (result[i] = []);
result[i].push(item[key]);
}
}
console.log(result[1]); // --> ["Foo"]
My take:
var sourceObject=[{id:0,name:'Tahir'},{id:0,name:'Ahmed'},{id:1,name:'David'},{id:1,name:'G'},{id:2,name:'TA'},{id:3,name:'DG'}];
function getNames(id){
var names=[],length=sourceObject.length,i=0;
for(i;i<length;i+=1){
if(sourceObject[i].id===id){
names[names.length]=sourceObject[i].name;
}
}
return names;
}
console.log(getNames(1));
What you want to do is walk the array of objects one time. Each time through, you want to check your new object to see if that id exists yet. If it does, add the name. If not, make a new entry for that id and add an array with one entry. Note, this doesn't handle duplicate names (it just adds it again).
var array = [{id:1, name:"test"},
{id:1, name:"another"},
{id:2, name:"something"}];
var result = {};
array.forEach(function(item) {
if (result[item.id]) {
result[item.id].push(item.name);
}
else {
result[item.id] = [item.name];
}
});
console.log(result[1]);