I have an array like this:
employees = [
{
"id": 1,
"shift_id": 1,
"days": {
"2012-03-01": 1,
"2012-03-02": 1,
"2012-03-03": 1,
"2012-03-04": 0,
"2012-03-05": 0,
"2012-03-06": 0
}},
{
"id": 2,
"shift_id": 1,
"days": {
"2012-03-01": 0,
"2012-03-02": 1,
"2012-03-03": 1,
"2012-03-04": 1,
"2012-03-05": 1,
"2012-03-06": 0
}},
{
"id": 3,
"shift_id": 2,
"days": {
"2012-03-01": 0,
"2012-03-02": 0,
"2012-03-03": 1,
"2012-03-04": 1,
"2012-03-05": 1,
"2012-03-06": 1
}}
];
is there a way to access an element in this array using the id value?
maybe something in jquery?
like $(employees('id = 1');
Just loop through your array and check for the id:
var yourId = 1;
for (var i = 0, len = employees.length; i < len; i++) {
if (employees[i].id == yourId) {
// ...
}
}
You can use a function like this, which filters the array appropriately:
var getEmployee = function (id) {
return employees.filter(function(i) { return i.id == id; });
};
You can use .grep() method documented here:
var employee = $.grep(employees, function(e) { return e.id == 1 })[0];
Well, there's a jQuery way of doing it:
var findElementById = function(elements, id) {
return $.grep(elements, function(e) { return e.id === id; })[0];
}
Still I wonder why don't you just index the source array by id instead.
Maybe you are looking for something like the below:
$.grep(employees, function(n){return n.id==1});
Or this:
$.each(employee, function(){
if(this["id"] == 2){
console.log(this);
}
});
As far as I am aware, in order to achieve that you would have to loop through them
Array.prototype.getObjectById = function(x){
var catcher = false, i = 0;
while(!catcher){
catcher = this[i].id == x ? this[i] : false;
i++;
}
return catcher;
}
This function should help. It will extend the array object so you can use it as myArray.getObjectbyId(id);
By design, this will return the first object that meets the criteria. You could extend it like so:
Array.prototype.getObjectsById = function(x){
var catcher = [], i = 0;
for(var i = 0; i < this.length; i++){
if(this[i].id == value){
catcher.push(this[i]);
}
i++;
}
return catcher.length == 1 ? catcher[0] : catcher;
}
This will return an array of objects if more than one object matches the criteria.
Array.prototype.getObjectsByAttribute = function(x, criteria){
if(!criteria){criteria = 'id';}
var catcher = [], i = 0;
for(var i = 0; i < this.length; i++){
if(this[i].criteria == value){
catcher.push(this[i]);
}
i++;
}
return catcher.length == 1 ? catcher[0] : catcher;
}
This extends it further to look for any criteria.
I know this question is old, but for future reference if anyone else stumbles upon this question ...
Instead of trying to over-engineer a function to parse/examine your JSON, consider changing the structure of your data to suit its purpose.
Consider the example in the question:
data = [ {
"id": 1,
"shift_id": 1,
"days": {
"2012-03-01": 1,
"2012-03-02": 1,
"2012-03-03": 1,
"2012-03-04": 0,
"2012-03-05": 0,
"2012-03-06": 0
}}, { .. }, {...} ]
Structuring the data in this way only gives you sequential access to the objects with no way to lookup an object by a particular index. Array indices are generally meaningless in this context.
data[0] => { id : 1, .. }
data[1] => { id : 2, .. }
What happens if the id is non-sequential or alphanumeric?
Using an array wont help you search any faster, you'll still have to loop...
Instead consider using a hash table/object:
{
'id1' => { id : 1 , data : { ... } },
'id99' => { id : 99, data : { ... } },
'id2' => { id : 2 , data : { ... } },
}
You can use a string value for the key and get direct access to the data by doing something like:
data['id2'] => { id : 2, ... }
Which will give you direct access to the data you want to find (by id). By simply re-organizing the structure of the data we were able to go from a O(n) search to an O(1) search.
Keep in mind that this method may work better for some solutions than others, and there are a number of other considerations to make.
This is just one approach to how you might solve a problem when you want to lookup data by a unique property.
The accepted answer is great - modified a bit for an AngularJS app:
$rootScope.getObjectsByAttribute = function(inarry,infldnm,infldval){
// This will iterate through a fetchAll sql result set and return rows where fldnm==fldval
// If it finds 1 row it returns a single object, if more than that it returns an array of objects
// Usage: result = $rootScope.getObjectsByAttribute(myarray,'myfldnm',myfldval);
if(!infldnm){infldnm = 'id';}
var catcher = [], i = 0;
for(i = 0; i < inarry.length; i++){
if(inarry[i][infldnm] == infldval){
catcher.push(inarry[i]);
}
}
return catcher.length == 1 ? catcher[0] : catcher;
}
Related
I am doing a particular task but it isnt dynamic. Below i have a eventList and a response from API. Based on the eventList, i have to rearrange the response and sort it.
For eg. below, i have eventList XM1, XM2, XM3, So i have to rearrange response, in such a way that eventTitle with XM1 becomes first element, eventTitle with XM2 is second element and XM3 is third element. And this will repeat till the last element of response is reached. In Below example, once id 1, 3, 2 are pushed sequentially object id 4 is left. But id with object 4 has eventTitle XM2. That means XM1 has to be filled with empty object and XM3 has to be filled with another empty object.
let eventList = [ "XM1", "XM2", "XM3" ];
let response = [
{ "id": 1, "eventTitle": "XM1" },
{ "id": 2, "eventTitle": "XM3" },
{ "id": 3, "eventTitle": "XM2" },
{ "id": 4, "eventTitle": "XM2" },
]
The result of this sequentially placing elements and filling the gaps with id=0 is shown below.
let sortResponse = [
{ "id": 1, "eventTitle": "XM1" },
{ "id": 2, "eventTitle": "XM2" },
{ "id": 3, "eventTitle": "XM3" },
{ "id": 0, "eventTitle": "XM1" },
{ "id": 4, "eventTitle": "XM2" },
{ "id": 0, "eventTitle": "XM3" },
]
Here is the code i use to sequentially sort elements and add empty objects in the output. But this is not dynamic. i always knew that my eventList will be 3 elements. but i want to make it dynamic so that even if my eventList is 10 elements, i should be able to sort and fill missing objects in it. Can someone please let me know how to achieve this dynamically
let sortResponse = []
if (eventList.length === 3 && response.length > 0) {
let fil1 = response.filter(function (el) {
return el.eventTitle === eventList[0];
});
let fil2 = response.filter(function (el) {
return el.eventTitle === eventList[1];
});
let fil3 = response.filter(function (el) {
return el.eventTitle === eventList[2];
});
let obj = { id: 0, eventTitle: "" };
let obj1 = { id: 0, eventTitle: "" };
//check if fil1 has most elements and use it to iterate through each fil1 and push fil2 and fil3
if (fil1.length >= fil2.length && fil1.length >= fil3.length) {
for (let j = 0; j < fil1.length; j++) {
sortResponse.push(fil1[j]);
if (!fil2[j]) {
obj.eventTitle = eventList[1];
}
sortResponse.push(fil2[j] ? fil2[j] : obj);
if (!fil3[j]) {
obj1.eventTitle = eventList[2];
}
sortResponse.push(fil3[j] ? fil3[j] : obj1);
}
}
//check if fil2 has most elements and use it to iterate through each fil2 and push fil1 and fil3
else if (fil2.length >= fil1.length && fil2.length >= fil3.length) {
for (let j = 0; j < fil2.length; j++) {
if (!fil1[j]) {
obj.eventTitle = eventList[0];
}
sortResponse.push(fil1[j] ? fil1[j] : obj);
sortResponse.push(fil2[j]);
if (!fil3[j]) {
obj1.eventTitle = eventList[2];
}
sortResponse.push(fil3[j] ? fil3[j] : obj1);
}
}
//check if fil3 has most elements and use it to iterate through each fil3 and push fil1 and fil2
else if (fil3.length >= fil1.length && fil3.length >= fil2.length) {
for (let j = 0; j < fil3.length; j++) {
if (!fil1[j]) {
obj.eventTitle = eventList[0];
}
sortResponse.push(fil1[j] ? fil1[j] : obj);
if (!fil2[j]) {
obj1.eventTitle = eventList[1];
}
sortResponse.push(fil2[j] ? fil2[j] : obj1);
sortResponse.push(fil3[j]);
}
}
}
This isn't particularly optimized since we're "finding" the next element over and over again in our loop, but it's pretty dynamic so it might work for you.
WARNING: This also will NOT terminate if your initial response object contains an event with an event title that is not in the eventList array. In that case, the loop will execute indefinitely and will just keep adding "filler" events to the new response array.
let eventList = [ "XM1", "XM2", "XM3" ];
let response = [
{ "id": 1, "eventTitle": "XM1" },
{ "id": 2, "eventTitle": "XM3" },
{ "id": 3, "eventTitle": "XM2" },
{ "id": 4, "eventTitle": "XM2" },
]
let newResponse = [];
let i = 0;
while(true) {
// Get the event title we are looking for. We'll have to manage looping through event titles kind of manually.
let currentEventTitle = eventList[i];
// Grab the index of the NEXT event that matches the current event title.
let nextEventIndex = response.findIndex( event => event.eventTitle === currentEventTitle );
// If our response has an event that matches, return that event from the current response array, otherwise we'll construct a "filler" event
let nextEvent = nextEventIndex !== -1 ? response.splice(nextEventIndex, 1)[0] : { "id": 0, "eventTitle": currentEventTitle };
// Push the found or constructed event to a new array.
newResponse.push(nextEvent);
// Now we'll need to manage our eventlist looping and exit condition.
// First increment our eventList index or start again from 0 if we've reached the end.
i++;
if(i === eventList.length) i = 0;
// Our exit condition is 1) if our starting response array is empty and 2) if we've gotten to the end of our event list
// which at this point means we've looped back around and our index is 0 again.
if(response.length === 0 && i === 0) break;
}
document.getElementById("result").innerText = JSON.stringify(newResponse, null, 4);
<pre id="result"></pre>
This question already has answers here:
How do I loop through or enumerate a JavaScript object?
(48 answers)
Closed 5 years ago.
I've a javascript object inside a variable data like:
data: Object {
aliquota: 23,
imponibileLordo: 300,
imponibileScontato: "",
imposta: 69
}
In another function i've to iterate the object using an index like:
for ( var index = 0; index < data.length; index++ ) {
var valueOfIndex = data[index];
console.log(valueOfIndex);
}
But I get error cause data[0], data[1], data[2], data[3] are not defined.
How can solve this? Important: i've to use a numeric INDEX for cycle for cause I do other operation based on index value.
UPDATE: Ok my goal is another. So i'll upload the script i'm using with the fix I DON'T LIKE but works. (See //ACTUAL FIX comment) Also the fiddle here: https://jsfiddle.net/am3ovL3b/5/
var array_iva = [];
var data = { "impo": 10, "aliq": 20, "other": 30 };
var column = { "title": "TEST 1", "data": data };
array_iva.push(column);
var data = { "impo": 40, "aliq": 50, "other": 60 };
var column = { "title": "TEST 2", "data": data };
array_iva.push(column);
var json_righe = [[ "Imponibile lordo" ], [ "Aliquota %" ], [ "Others" ] ];
for ( var i = 0; i < array_iva.length; i++ ) {
var titolo_colonna_iva = {};
titolo_colonna_iva['title'] = array_iva[i]['title'];
for ( j = 0; j < json_righe.length; j++ ) { // for each
var riga = json_righe[j];
for ( var k = 0; k < array_iva.length; k++ ) { // EMPTY DEFAULT
riga.push("");
}
// ACTUAL FIX
if ( j == 0 ) {
riga[(i+1)] = array_iva[i]['data']['impo'];
} else if ( j == 1 ) {
riga[(i+1)] = array_iva[i]['data']['aliq'];
} else if ( j == 2 ) {
riga[(i+1)] = array_iva[i]['data']['other'];
}
//END ACTUAL FIX
/*
THIS DOESn?T WORK
riga[(i+1)] = array_iva[i]['data'][j];
*/
json_righe[j] = riga;
}
}
You can use Object.keys to get an array of all keys and loop trough this array to console.log value correponding to each key:
var data = {
aliquota: 23,
imponibileLordo: 300,
imponibileScontato: "",
imposta: 69
};
Object.keys(data).forEach(key => console.log(data[key]));
To iterate an object use for ..in
var data = {
aliquota: 23,
imponibileLordo: 300,
imponibileScontato: "",
imposta: 69
}
for (var index in data) {
var valueOfIndex = data[index];
console.log(valueOfIndex);
}
i've to use a numeric INDEX for cycle for cause I do other operation based on index value.
Then you'll want to reorganize your logic and code to use an array instead of an object, or at least to have your own array of property names in a defined order and loop through that. Although object properties have an order as of ES2015, it's not an order you should use as it depends on how the object was created and what the names of the properties are (e.g., do they look like array indexes or not).
You can loop through the object's properties in the ES2015+ order by using Object.getOwnPropertyNames on the object and looping through the strings in the returned array, e.g.:
Object.getOwnPropertyNames(data).forEach((name, index) => {
// `name` will be the property name,
// `index` will be its index in the property order
// ...
});
...but again, it's not a good idea to rely on those being in any particular order.
I'm new to JavaScript and I'm really lost here. Here is some data produced by PHP json_encode() (and limited to most pertinent keys) :
[
{
"product_option_id":"229",
"product_option_value":
[
{
"product_option_value_id":"21",
"option_value_id":"51",
"price":"1,22 €",
"price_prefix":"+"
},
{
"product_option_value_id":"22",
"option_value_id":"52",
"price":false,
"price_prefix":"+"
},
{
"product_option_value_id":"23",
"option_value_id":"53",
"price":"2,42 €",
"price_prefix":"+"
}
],
"option_id":"14",
"type":"radio",
"value":""
},
{
"product_option_id":"228",
"product_option_value":
[
{
"product_option_value_id":"19",
"option_value_id":"49",
"price":"1,22 €",
"price_prefix":"+"
},
{
"product_option_value_id":"20",
"option_value_id":"50",
"price":"2,42 €",
"price_prefix":"+"
}
],
"option_id":"13",
"type":"select",
"value":""
}
]
I need to access price and price_prefix values (in JavaScript) knowing product_option_id and product_option_value_id.
How do I do that ? Should I go for a loop ?
Update :
Thanks for replies. Unless I missed something, it appears that in my case arrays (as ugly as they may be…) are much more efficient than all the proposed solutions (I'll try another approach, formatting a JSON object corresponding to my needs with PHP rather than using the "default" one, but it's off topic here). Though I'm not fond of adding libraries and it's a bit slower than most other solutions, I'll accept Matt's solution because it really seems to make life easier as far as JSON access is concerned. But it should be noted that Yeldard and Barmar's (almost cloned) solutions are faster than other propositions.
lodash would make this easier and neater. It provides _.find or _.filter depending on if your id's are unique or not.
var record = _.find( data_structure, {
"product_option_id": "229"
})
if ( !record ) throw new Error("Record not found");
var value = _.find( record.product_option_value, {
"product_option_value_id":"22"
})
if ( !value ) throw new Error("Value not found");
console.log( "price[%s] prefix[%s]", value.price, value.price_prefix )
Demo
For more complex data selection, you might want to look at sift.js. It's based on mongodb's query system.
var records = sift({
"product_option_id": "229",
"product_option_value": {
$elemMatch: {
"product_option_value_id": "22"
}
}
},
data_structure
)
you can do like this
for(var i in jsonData) {
var item = jsonData[i];
if(item.product_option_id == 229) {
for(var j in item.product_option_value){
var item1 = item.product_option_value[j];
if(item1.product_option_value_id == 21) {
//your item here
break;
}
}
break;
}
}
This should do it:
var productOptionId = 229;
var productOptionValue = 22;
var matchingOuter = yourData.filter(function(i){
return i.product_option_id === productOptionId;
})[0];
if (matchingOuter) {
var matchingInner = matchingOuter.product_option_value.filter(function(i){
return i.product_option_value === productOptionValue;
})[0];
}
If a matching item exists it will be assigned to matchingInner
Following would do:
function getProductValues(products, product_option_id, product_option_value_id) {
if (!product_option_id || !product_option_value_id) {
return;
}
return products.filter(function(product) {
return +product.product_option_id === product_option_id;
}).map(function (product) {
var option_values = product.product_option_value;
return option_values.filter(function (option) {
return +option.option_value_id === product_option_value_id;
})[0] || [];
})[0] || [];
}
Usage:
getProductValues(data, 229, 51)
Result:
{product_option_value_id: "21", option_value_id: "51", price: "1,22 €", price_prefix: "+"}
Use filter on the main array to grab the right object, filter again on the option_value_id, then map on the returned array to get a single price/prefix object. map and filter both return arrays which is why you see the code picking up the first element ([0]) in a couple of places.
function getData(data, options) {
return data.filter(function (product) {
return product.product_option_id === options.id;
})[0].product_option_value.filter(function (details) {
return details.product_option_value_id === options.optionId;
}).map(function(el) {
return { price: el.price, prefix: el.price_prefix }
})[0];
}
getData(data, { id: '229', optionId: '23' }); // { price: "2,42 €", prefix: "+" }
DEMO
Use nested loops to search through the main array and the sub-arrays, looking for the matching element.
function find_product(product_option_id, product_option_value_id) {
for (var i = 0; i < products.length; i++) {
var product = products[i];
if (product.product_option_id == product_option_id) {
for (var j = 0; j < product.product_option_value.length; j++) {
var value = product.product_option_value[j];
if (value.product_option_value_id == product_option_value_id) {
return { price: value.price, price_prefix: value.price_prefix }
}
}
}
}
}
Yes, you need to enumerate through the array and find your items:
Here is the working code which outputs price_prefix and price of product with product_option_id = 228 and product_option_value_id = 19. You can replace these values with your own.
for (var i = 0; i < obj.length; i++) // Enumerate through array
{
var item = obj[i];
if (item.product_option_id === "228") // Filtering items by product_option_id
{
// When necessary product_option_id found
for (var j = 0; j < item.product_option_value.length; j++) // Enumerate through its products
{
var productItem = item.product_option_value[j];
if (productItem.product_option_value_id === "19") // Filtering by product_option_value_id
{
// here it is. productItem is found! do whatever you want with it
alert(productItem.price_prefix + " " + productItem.price);
}
}
}
}
Working JSFiddle demo.
$.each(constructions, function(i,v) {
if ($.inArray(v.name, map[ii].buildings) == -1) {//stuff}
};
Where constructions is an array of objects, each with a unique name. map[ii].buildings is an array containing some of these objects. I want to iterate each object in constructions, checking if its name parameter appears in the objects of map[ii].buildings.
The above code works if the each element in the map[ii].buildings array is just the text string of the object name, but not if the element is the entire object.. close, but no dice >.<
Try using $.grep() instead of $.inArray(); you can specify a function to do the filtering for you.
Instead of checking for -1, you check whether the array that $.grep() returns has length == 0
Simple example: (would be easier if you posted the code / example of what "constructions" objects look like)
var constructions = [{
Name: "Mess hall",
SqFt: 5000
}, {
Name: "Infirmary",
SqFt: 2000
}, {
Name: "Bungalow",
SqFt: 2000
}, {
Name: "HQ",
SqFt: 2000
}];
var buildings = [{
Name: "Infirmary",
SqFt: 2000
}, {
Name: "HQ",
SqFt: 2000
}];
// found buildings will be list of items in "constructions" that is not in "buildings"
var foundBuildings = $.grep(constructions, function (constructionsItem) {
return $.grep(buildings, function (buildingsItem) {
return buildingsItem.Name === constructionsItem.Name
}).length == 0; // == 0 means "not in", and > 0 means "in"
});
// this just renders the results all pretty for ya
$.each(foundBuildings, function (idx, item) {
$("#output").append("<div>" + item.Name + "</div>");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='output'></div>
Example jsFiddle: http://jsfiddle.net/eLeuy9eg/3/
The non-jQuery way of doing this would be to use filter. Something like this:
// pass in an array and the key for which you want values
// it returns an array of those values
function getValues(arr, key) {
return arr.map(function (el) { return el[key]; });
}
function notFoundIn(arr, arr2) {
// grab the names of the buildings
var buildings = getValues(arr2, 'name');
// grab the names from the construction objects and filter
// those that are not in the building array
return getValues(arr, 'name').filter(function (el) {
return buildings.indexOf(el) === -1;
});
}
notFoundIn(constructions, buildings); // eg [ "one", "three" ]
DEMO
You could even add a new method to the array prototype. With this one you can use either simple arrays, or arrays of objects if you pass in a key. Note in this example I've replaced map and filter with loops that perform the same functions, but faster (see comments):
function getValues(arr, key) {
var out = [];
for (var i = 0, l = arr.length; i < l; i++) {
out.push(arr[i][key]);
}
return out;
}
if (!Array.prototype.notFoundIn) {
Array.prototype.notFoundIn = function (inThisArray, key) {
var thisArr = key ? getValues(this, key) : this;
var arrIn = key ? getValues(inThisArray, key) : inThisArray;
var out = [];
for (var i = 0, l = thisArr.length; i < l; i++) {
if (arrIn.indexOf(thisArr[i]) === -1) {
out.push(thisArr[i]);
}
}
return out;
}
}
constructions.notFoundIn(buildings, 'name');
[1, 2, 3].notFoundIn([2]); // [1, 3]
DEMO
I am trying to figure out an efficient way to remove objects that are duplicates from an array and looking for the most efficient answer. I looked around the internet everything seems to be using primitive data... or not scalable for large arrays. This is my current implementation which is can be improved and want to try to avoid labels.
Test.prototype.unique = function (arr, artist, title, cb) {
console.log(arr.length);
var n, y, x, i, r;
r = [];
o: for (i = 0, n = arr.length; i < n; i++) {
for (x = 0, y = r.length; x < y; x++) {
if (r[x].artist == arr[i].artist && r[x].title == arr[i].title) {
continue o;
}
}
r.push(arr[i]);
}
cb(r);
};
and the array looks something like this:
[{title: sky, artist: jon}, {title: rain, artist: Paul}, ....]
Order does not matter, but if sorting makes it more efficient then I am up for the challenge...
and for people who do not know o is a label and it is just saying jump back to the loop instead of pushing to the new array.
Pure javascript please no libs.
ANSWERS SO FAR:
The Performance Test for the answers below:
http://jsperf.com/remove-duplicates-for-loops
I see, the problem there is that the complexity is squared. There is one trick to do it, it's simply by using "Associative arrays".
You can get the array, loop over it, and add the value of the array as a key to the associative array. Since it doesn't allow duplicated keys, you will automatically get rid of the duplicates.
Since you are looking for title and artist when comparing, you can actually try to use something like:
var arrResult = {};
for (i = 0, n = arr.length; i < n; i++) {
var item = arr[i];
arrResult[ item.title + " - " + item.artist ] = item;
}
Then you just loop the arrResult again, and recreate the array.
var i = 0;
var nonDuplicatedArray = [];
for(var item in arrResult) {
nonDuplicatedArray[i++] = arrResult[item];
}
Updated to include Paul's comment. Thanks!
Here is a solution that works for me.
Helper functions:
// sorts an array of objects according to one field
// call like this: sortObjArray(myArray, "name" );
// it will modify the input array
sortObjArray = function(arr, field) {
arr.sort(
function compare(a,b) {
if (a[field] < b[field])
return -1;
if (a[field] > b[field])
return 1;
return 0;
}
);
}
// call like this: uniqueDishes = removeDuplicatesFromObjArray(dishes, "dishName");
// it will NOT modify the input array
// input array MUST be sorted by the same field (asc or desc doesn't matter)
removeDuplicatesFromObjArray = function(arr, field) {
var u = [];
arr.reduce(function (a, b) {
if (a[field] !== b[field]) u.push(b);
return b;
}, []);
return u;
}
and then simply call:
sortObjArray(dishes, "name");
dishes = removeDuplicatesFromObjArray(dishes, "name");
Basic sort-then-unique implementation, fiddle HERE:
function unique(arr) {
var comparer = function compareObject(a, b) {
if (a.title == b.title) {
if (a.artist < b.artist) {
return -1;
} else if (a.artist > b.artist) {
return 1;
} else {
return 0;
}
} else {
if (a.title < b.title) {
return -1;
} else {
return 1;
}
}
}
arr.sort(comparer);
console.log("Sorted: " + JSON.stringify(arr));
for (var i = 0; i < arr.length - 1; ++i) {
if (comparer(arr[i], arr[i+1]) === 0) {
arr.splice(i, 1);
console.log("Splicing: " + JSON.stringify(arr));
}
}
return arr;
}
It may or may not be the most efficient, and should be entirely scalable. I've added some console.logs so you can see it as it works.
EDIT
In the interest of saving on the space the function used, I did that for loop at the end, but it seems likely that didn't properly find only unique results (depsite it passing my simple jsfiddle test). Please try replacing my for loop with the following:
var checker;
var uniqueResults = [];
for (var i = 0; i < arr.length; ++i) {
if (!checker || comparer(checker, arr[i]) != 0) {
checker = arr[i];
uniqueResults.push(checker);
}
}
return uniqueResults;
I use this function. its not doing any sorting, but produces result. Cant say about performance as never measure it.
var unique = function(a){
var seen = [], result = [];
for(var len = a.length, i = len-1; i >= 0; i--){
if(!seen[a[i]]){
seen[a[i]] = true;
result.push(a[i]);
}
}
return result;
}
var ar = [1,2,3,1,1,1,1,1,"", "","","", "a", "b"];
console.log(unique(ar));// this will produce [1,2,3,"", "a", "b"] all unique elements.
Below is Henrique Feijo's answer with ample explanation and an example that you can cut and paste:
Goal: Convert an array of objects that contains duplicate objects (like this one)...
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
... Into an array of objects without duplicate objects (like this one):
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
Explanation provided in the comments:
var allContent = [{
"id": 10620,
"name": "Things to Print"
}, {
"id": 10620,
"name": "Things to Print"
}, {
"id": 4334,
"name": "Interesting"
}]
//Put Objects Into As Associative Array. Each key consists of a composite value generated by each set of values from the objects in allContent.
var noDupeObj = {} //Create an associative array. It will not accept duplicate keys.
for (i = 0, n = allContent.length; i < n; i++) {
var item = allContent[i]; //Store each object as a variable. This helps with clarity in the next line.
noDupeObj[item.id + "|" + item.name] = item; //This is the critical step.
//Here, you create an object within the associative array that has a key composed of the two values from the original object.
// Use a delimiter to not have foo+bar handled like fo+obar
//Since the associative array will not allow duplicate keys, and the keys are determined by the content, then all duplicate content are removed.
//The value assigned to each key is the original object which is along for the ride and used to reconstruct the list in the next step.
}
//Recontructs the list with only the unique objects left in the doDupeObj associative array
var i = 0;
var nonDuplicatedArray = [];
for (var item in noDupeObj) {
nonDuplicatedArray[i++] = noDupeObj[item]; //Populate the array with the values from the noDupeObj.
}
console.log(nonDuplicatedArray)
For those who love ES6 and short stuff, here it's one solution:
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" }
];
Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Jon" },
{ title: "cry", artist: "Jon" }
];
const unique = Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
console.log(`New array length: ${unique.length}`)
console.log(unique)
The above example only works for a unique title or id. Basically, it creates a new map for songs with duplicate titles.
Below code compares object with JSON as String format and removes duplicates and works fine with simple arrays.
Array.prototype.unique=function(a){
return function(){
return this.filter(a)
}
}(
function(a,b,c){
var tmp=[];
c.forEach(function(el){
tmp.push(JSON.stringify(el))
});
return tmp.indexOf(JSON.stringify(a),b+1)<0
})
If you are using underscore js, it is easy to remove duplicate object.
http://underscorejs.org/#uniq
function remove_duplicates(objectsArray) {
var arr = [], collection = [];
$.each(objectsArray, function (index, value) {
if ($.inArray(value.id, arr) == -1) {
arr.push(value.id);
collection.push(value);
}
});
return collection;
}