i cannot find a solution of my issue. i probably making things more complicated.
here is the array:
var Statistics = {
"STAT 1 COLUMNS" : ["Date","Group Name","Product Name","Version","Version Date","Status","Total","Total L0","Total L1","Total L2","To be validated","Created","Updated"],
"STAT 2 TITLE" : ["12/12/2013","Led Zeppelin","roofies","V5.3","2013-08-13 ","ACCEPTED <br/>(2013-9-10)","774","334","3","437","20","57","102"],
"STAT 3 TITLE" : ["22/11/2014","Deep Purple","upper","V1","2006-01-01 "," ","3","1","0","2","1"," "," "],
...
}
i would like to get the object name (such as 'STAT 1 COLUMNS', 'STAT 2 TITLE', 'STAT 3 TITLE'..) for a specific object, by specifing the index.
for instance, givemepleasethenameoftheobject('2') -> "STAT 3 TITLE"
can you please give me a hand?
Try with:
function givemepleasethenameoftheobject(index, data) {
var i = 0;
for ( var k in data ) {
if ( index == i++ ) {
return k;
}
}
}
var result = givemepleasethenameoftheobject(2, Statistics);
This should achieve what you need:
function getStatisticName(index)
{
var count = 0;
for(var i in Statistics)
{
if(count == index)
return i;
count++;
}
}
See this jsFiddle
Try the 'Object.keys();' function.
Object.keys(Statistics); // ['STAT 1 COLUMNS', 'STAT 2 TITLE', 'STAT 3 TITLE'];
You can loop through the members of an object like this:
for (var key in Statistics) {
console.log(key);
}
However, you can not reliably access them by index like that. The members in an object is not guaranteed to remain in the same order that you create them, and different browsers actually do order the members differently.
If you want to access the member names by index in a predictable way, you would need to get all names and then sort them:
function givemepleasethenameoftheobject(index) {
var keys = [];
for (var key in Statistics) {
keys.push(key);
}
keys.sort();
return keys[index];
}
If you don't need to be compatible with older browsers (e.g. Internet Explorer 8), you can use the Object.Keys method:
function givemepleasethenameoftheobject(index) {
var keys = Object.keys(Statistics);
keys.sort();
return keys[index];
}
Object keys order is not guaranteed in JavaScript, so gimmeTheKey(Statistics, 2) is not guaranteed to return "STAT 3 TITLE".
However:
function gimmeTheKey( obj, idx ){
return Object.keys( obj )[idx];
}
Related
The array looks like:
var test = [
{
Time: new Date(1000),
psi:100.0
},
{
Time: new Date(1000),
psi:200.0
},
{
Time: new Date(2000),
psi:200.0
}
]
The function looks like (the function was copied from some online resource, couldn't find the exact reference.)
function uniqTimetable(nums){
console.log(nums); //log#1
var length = nums.length;
var count = 0;
for (var i =0; i< length-1; i++){
if (nums[count].Time.getTime() !== nums[i+1].Time.getTime()){
count ++;
nums[count] = nums[i+1];
}
}
nums.length = count + 1;
console.log(nums); // log #2
}
uniqTimetable(test);
console.log(test);// log #3
Are there any problems of
copy one object to the other array member by this linenums[count] = nums[i+1]
rescale the array length by this linenums.length = count + 1
?
With electron/node.js, the output looks a bit weird.
In log#1, it shows the array length is 2 instead of 3. Something seems wrong with the function. Any suggestions welcome.
Thanks in advance.
If I understood the problem, you can solve it in one line function:
const test = [{
Time: new Date(1000),
psi: 100.0
},
{
Time: new Date(1000),
psi: 200.0
},
{
Time: new Date(2000),
psi: 200.0
}
]
const unique = test.filter(({Time}, i, array) =>
!array.find((item, j) => item.Time.getTime() === Time.getTime() && j > i));
console.log(unique);
(I assumed psi is not relevant)
It uses find and filter array's methods.
function removeDuplicates(myArr, prop) {
return myArr.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
});
}
removeDuplicates(test,"Time")
Using the filter function of javascript, to return the List of only unique elements.
I like #Akin's answer! But unfortunately the .indexOf() function does not work for Date objects with the same value, since each object is still considered to be different and the .indexOf() function will always find the index of the Date object itself and never another "copy". To overcome this I convert the Date object back to milliseconds before collecting the values in an array (tst). I do this with myArr.map(mapObj => mapObj[prop].getTime()) before I go into the .filter function.
As the .getTime() method will only work for Date objects it does not make sense to keep the property prop as an argument. Instead I hardcoded the .Time property into the code.
Edit:
By coercing a numerical data type with a unary operator + for the .Time property I can leave out the .getTime() method which will be applied implicitly.
var test = [{Time: new Date(1000), psi:100.0},
{Time: new Date(1000), psi:200.0},
{Time: new Date(2000), psi:200.0}];
function Cars10m_remDups(myArr) {
let tst=myArr.map(o=>+o.Time);
return myArr.filter((o, i)=>tst.indexOf(+o.Time)===i);
}
// for comparison: --> will list all three objects!
function Akin_remDups(myArr, prop) {
return myArr.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
});
}
// Zero's one-liner works too, here: my shortened version
const Zero_remDups = myArr => myArr.filter(({Time}, i, array) =>
!array.find((item, j) => +item.Time-Time==0&&i>j));
// also: with "i>j" I pick the first unique (Zero chose the last)
console.log('Cars10m:',Cars10m_remDups(test));
console.log('Akin:',Akin_remDups(test,"Time"));
console.log('Zero:',Zero_remDups(test));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I'm in a situation where I need to store some data in an object, but I can only have a set number of that data due to browser limitations. Since my app also needs to be able to get this data, I am storing it in an object where the keys of the properties are identifiers.
The data looks like this:
memory = {
13: {
last_updated: 241,
...
},
26: {
last_updated: 363,
....
}
}
last_updated would be a Date.now() string of course. This object can not have more than 6 properties. When it reaches that length, I need to start replacing the oldest properties with new data. How do I get the oldest property of the object?
One way would be to just sort the objects keys by the last updated timestamp, and pop of the last one, the oldest one
var oldest = memory[Object.keys(memory).sort(function(a,b) {
return memory[b].last_updated - memory[a].last_updated
}).pop()];
You can do something like this:
var obj = {};
for(var i = 0;i < 5; i++){
obj[i] = {date:Date.now() + i};
}
function addNew(date){
if(obj.length < 5){
obj[obj.length] = {date:date};
return;
}
var arr = [];
for(var prop in obj){
arr.push({prop:prop,date:obj[prop].date})
}
var last = arr.sort(function(a, b){return b.date-a.date})[0].prop;
obj[last].date = date;
}
addNew(Date.now() + 100);
console.log(obj);
You need to add new properties to the object only by using the addNew(...) function in order for this to work.
This would take the newest 6 items from the memory object.
var freshMemory = Object.keys(memory)
.map(function (k) { return [k, data[k]] })
.sort(function (a, b) { return b[1].last_updated - a[1].last_updated; })
.slice(0, 6)
.reduce(function (o, v) { o[v[0]] = v[1]; return o; }, {});
A short explanation
The Object.keys combined with the .map method will transfer the object to an array containing two-tuples (the key and the value)
then the .sort will sort the array by last_updated in reverse order
then the .slice will take the first 6 items
and finally .reduce will convert the array with two-tuples back to an object.
Best way to count the number of objects in a array with different object property p values.
function([{"p":"a"},{"p":"b"},{"p":"a"}]){
// some code
}
// in this case return 2
You can use Array.prototype.filter() to keep values that you want. In this case, you must create a variable temp for storing duplicate values and also within the filter function returns true if it does not exist in case. So you have a new array of unique values.
var arr = [{"p":"a"},{"p":"b"},{"p":"a"}], temp = [];
var arrUniques = arr.filter(function(obj){
return temp.indexOf(obj.p) === -1 ? !!temp.push(obj.p) : false
});
alert(arrUniques.length)
With a Map:
var props = new Map();
for (var i = 0; i < array.length; i++) {
var prop = array[i].p,
count = props.get(prop) || 0;
props.set(prop, count + 1);
}
var size = props.size;
If your properties can be safely casted to strings, you can use a common object:
var props = {};
...
var size = Object.keys(props).length;
Otherwise, Map is your answer.
function getUniquePropertyCount(a, p) {
return a.reduce(function (res, el) {
!~res.indexOf(el[p]) && res.push(el[p]);
return res;
}, []).length;
}
document.write(getUniquePropertyCount([{ "p": "a" }, { "p": "b" }, { "p": "a" }], 'p'));
I suppose this is one of those questions where if you ask four programmers, you'll get five answers.
The other answers so far show some interesting approaches. I would watch out for browser compatibility; for example Map() is only available in the newest browsers, not in IE 10 or prior.
So here's one more solution. It's a bit more code, but it's pretty easy to understand, and it works in every browser:
function countUniqueProperties( key, array ) {
var count = 0, values = {};
for( var i = 0; i < array.length; ++i ) {
var value = array[i][key];
if( ! Object.prototype.hasOwnProperty.call( values, value) ) {
++count;
values[value] = true;
}
}
return count;
}
countUniqueProperties( 'p', [ {p:'a'}, {p:'b'}, {p:'a'} ] );
The one complicated part here is the Object.prototype.hasOwnProperty.call(values,value). You could just use values.hasOwnProperty(value), but that would fail if one of your property values was the string "hasOwnProperty":
countUniqueProperties( 'p', [ {p:'a'}, {p:'hasOwnProperty'}, {p:'a'} ] );
Using the longer form avoids this issue.
lodash is nice for things like this.
Use
_.uniq([{"p":"a"},{"p":"b"},{"p":"a"}]).length
and it'll return 2.
I have built an object in PHP, used JSON_encode function and send it as a JSON string to my JS script via ajax. Then I convert it back to an object. The problem I am having is that I wanted to keep the object in the order that it was originally created in. Please see this picture of what the object looks like once I get it into JS:
When I created the object, it was sorted by the customer field alphabetically. The customer name starting with A would come first, B second, etc. As you can see, now, the first element of the object as customer starting with S. It looks like somehow it got automatically sorted by the key of the top-level object, which is an integer, so I understand why this happened.
So i want to do is re-sort this object so that all the sub-objects are sorted by the customer field alphabetically. Is this possible? If so, how do I do it?
Thanks!
I've changed Fabricio Matée answer to become more flexible and return the sorted object.
function alphabetical_sort_object_of_objects(data, attr) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop][attr].toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
var result = [];
for (var i=0, l=arr.length; i<l; i++) {
var obj = arr[i];
delete obj.tempSortName;
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop;
}
}
var item = obj[id];
result.push(item);
}
return result;
}
Then just call the function like this
your_object = alphabetical_sort_object_of_objects(your_object, 'attribute_to_sort');
It's probably the difference between a JavaScript Object and a JavaScript Array. Objects are more like hash tables, where the keys aren't sorted in any particular order, whereas Arrays are linear collections of values.
In your back end, make sure you're encoding an array, rather than an object. Check the final encoded JSON, and if your collection of objects is surrounded by {} instead of [], it's being encoded as an object instead of an array.
You may run into a problem since it looks like you're trying to access the objects by an ID number, and that's the index you want those objects to occupy in the final array, which presents another problem, because you probably don't want an array with 40,000 entries when you're only storing a small amount of values.
If you just want to iterate through the objects, you should make sure you're encoding an array instead of an object. If you want to access the objects by specific ID, you'll probably have to sort the objects client-side (i.e. have the object from the JSON response, and then create another array and sort those objects into it, so you can have the sorted objects and still be able to access them by id).
You can find efficient sorting algorithms (or use the one below from ELCas) easily via Google.
Here's a generic iteration function which pushes all objects into an array and sorts them by their customer property in a case-insensitive manner, then iterates over the sorted array:
function iterate(data) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop].customer.toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
for (var i = 0, l = arr.length; i < l; i++) {
var obj = arr[i];
delete obj.tempSortName;
console.log(obj);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop; //gets the obj "index" (id?)
}
}
console.log(id);
var item = obj[id];
console.log(item.customer);
//do stuff with item
}
}
Fiddle
sortObject(object){
if(typeof object === 'object'){
if(object instanceof Date){
return object;
}
if(object instanceof Array){
return object.map(element => this.sortObject(element));
} else {
return Object.keys(object).sort().reduce((result, key) => {
if(object[key] && object[key] !== null) {
result[key] = this.sortObject(object[key]);
}
return result;
}, {});
}
}
return object;
}
I'm using array.sort to sort an array of objects.
Is there someway to determine if the order of those objects changed other than doing a comparison myself? Some in-built JS function? I don't need to know the # of changes, just that there was at least 1 change.
Update:
I'm sorting custom objects, e.g.:
[
{ 'value' : 5, 'name' : 'foo'},
{ 'value' : 3, 'name' : 'bar'},
{ 'value' : 10, 'name' : 'js'}
]
Update 2:
I'm considering adding an additional custom property 'order' as I generate the objects and then checking to see if 'order' is or isn't sequential after the .sort. Is there a faster/better method?
There is nothing built in that does what you are asking. If it is a simple array you can just use join/toString() and compare the two final strings. If the array contains objects, probably would use JSON.stringify and compare.
var myArray1 = [1,2,3,4,5],
myArray2 = [2,1,3,4,5],
myArray1_sorted = myArray1.slice().sort(),
myArray2_sorted = myArray2.slice().sort();
//Check to see if the strings are the same or different
console.log( myArray1_sorted.toString() === myArray1.toString() ); //true - sort should not change anything
console.log( myArray2_sorted.toString() === myArray2.toString() ); //false - sort should have changed order
If you don't want to mess with two copies of the array, check the array before starting the sort.
You can loop through the array and return true if every item is in its sorted position,
(compares 'less' than the next item) or false as soon as one item is detected in the wrong position.
Since you are using objects, the comparison code depends on the way you are sorting the objects.
From Array.sort docs:
array.sort([compareFunction])
So it is obvious, there is no built-in solution/method for detecting whether at least one element has changed its position during the sorting. So you need to write your own method:
function isAnyElementChangedItsPosition( unsortedArray, sortedArray ){
for( var i = 0; i < unsortedArray.length; ++i){
if( unsortedArray[i] !== sortedArray[i] ){
return true;
}
}
return false;
}
You have to compare the arrays somehow. You can easily clone an array and make the check:
var arr = [5, 4, 1, 6]
var arrBefore = arr.slice(0);
arr.sort()
for(var i =0; i< arr.length; i++) {
if (arrBefore[i] !== arr[i]) {
// a change was made
}
}
In short: no built-in function, you've gotta check for equality.
Here's one way to check for equality:
function arraysEqual(a, b) {
// Are the lengths the same?
var i = a.length;
if (i !== b.length)
return false;
// Are all the values the same?
while (i --) {
if (a[i] !== b[i])
return false;
}
}
Note that this doesn't check if they're arrays; arraysEqual("abc", ["a", "b", "c"]) is true. You can add this check if you want.
There's not a built-in function to do what you want.
How about this:
function isArraySorted(array) {
if (!array.length) {
return true;
}
var lastElement = array[0];
for (var i = 1; i < array.length; i++) {
if (array[i] <= lastElement) {
return false;
}
lastElement = array[i];
}
return true;
}
alert(isArraySorted([1,2,3]) + " " + isArraySorted([1,2,3,2.5]));
var array = [1,2,3];
if (!isArraySorted(array)) {
// No need to do the sort if the array is already sorted.
array.sort();
}
Not duplicating data, becase strings and parallel arrays do.
function chkOrder(a) {
for(var i =1; i< a.length; i++)
if (a[i-1] > a[i]) return false;
return true;
}
you might need to work on th ">" sign if you reverse the order
this will also return false (not ordered) on first occourence
if we can control the contained objects then we can control changes in the objects and fire a parent sort
function O(parent,data) {//initialize with parent and value array/object
this.parent=parent;
this.data=data;
//shortcurt to sort parent
this.sort=function()
{console.log("sortingparent");this.parent.sort(this.parent.sortfunc);}
this.setData=function(data) {
this.data=data;
this.sort();
}
//if changes can be groupped then is more efficient to signal parent dirty and sort latter
this.setKey=function(key,value) {//change value in the data
if (key==parent.sortkey&&value!=this.data[key]) {
this.data[key]=value;
this.sort();
} else this.data[key]=value;
}
this.parent.push(this);
this.sort();
return this;
}
//-------
//using a simple array, this could also be and object and have specific func's
var arr=[];
//example, sort by name, ascending
arr.sortkey="name";
//closure to build a sort predicate bound to the used key
function setkey(key) {return function(a,b) {return a.data[key]>b.data[key];}}
arr.sortfunc=setkey(arr.sortkey);
var b=new O(arr,{name:"B",value:0});
var c=new O(arr,{name:"C",value:2});
var a=new O(arr,{name:"A",value:1});
var d=new O(arr,{name:"D",value:3});
console.log("changing value");
a.setKey("value",100);//when not sorting by value its the same as a.data.value=100
console.log("changing name");
a.setKey("name","X");//this will fire parent sort
for(n=0;n<arr.length;n++) console.log(arr[n].data.name,"=",arr[n].data.value);
var data = [
{ 'value' : 5, 'name' : 'foo'},
{ 'value' : 3, 'name' : 'bar'},
{ 'value' : 10, 'name' : 'js'}
];
var changed = sortAndReport(data, byValue);
// sortAndReport :: [a], (a, a -> Number) -> Boolean
// Sorts an array according to the provided Array.prototype.sort
// compare function and returns a Boolean indicating whether
// sorting changed the order of the array.
function sortAndReport(a, fn) {
var changed = false;
a.sort(function (a, b) {
var sortResult = fn(a, b);
changed = sortResult > 0;
return sortResult;
});
return changed;
}
// byValue :: { value :: Number }, { value :: Number } -> Number
function byValue(a, b) {
return a.value - b.value;
}