get key of a object at index x - actionscript-3

How to get the key at specified index of a object in Flex?
var screenWindowListObject:Object = {
'something' : 'awesome',
'evenmore' : 'crazy',
'evenless' : 'foolish'
};
I want key at index 1 i.e evenmore.
In JavaScript it can be possible by using the following code.
var keys = Object.keys(screenWindowListObject);
console.log(keys[1]); // gives output 'evenmore'
Is there any equivalent in Flex?
I have an object with unique keys. Values are not unique. I am displaying the values in DropDownList by adding them to an Array Collection. I have to get the key from the Object based on the selected index.

According to Adobe, "Object properties are not kept in any particular order, so properties may appear in a seemingly random order." Because of this, you'll have to invent your own order. This can be achieved by populating an array with your keys, and then sorting that.
function getKeyOrder(hash:Object, sortType:int = 3):Array {
// Returns an array with sorted key values.
/*
1 = CASEINSENSITIVE
2 = DESCENDING
3 = ASCENDING
4 = UNIQUESORT
8 = RETURNINDEXEDARRAY
16 = Array.NUMERIC
*/
var order:Array = [];
for (var k:String in hash) {
order.push(k);
}
var reverse:Boolean = false;
if (sortType == 3) {
reverse = true;
sortType = 2;
}
order.sort(sortType)
if (reverse) { order.reverse(); }
return order;
}
var screenWindowListObject:Object = {
'something' : 'awesome',
'evenmore' : 'crazy',
'evenless' : 'foolish'
};
var orderedKeys:Array = getKeyOrder(screenWindowListObject);
for each (var key in orderedKeys) {
trace(key + ":" + screenWindowListObject[key]);
}
/* Results in...
evenless:foolish
evenmore:crazy
something:awesome
*/
trace("Index 0 = " + screenWindowListObject[orderedKeys[0]])
// Index 0 = foolish
getKeyOrder() returns an array with your keys in ascending order by default. This way, you'll be guaranteed to always have the same sequence of keys, and be able to pull up the index you're looking for. Just be wary when adding more keys, as it will shift each entry depending on where it shows up in the sort.

JavaScript's Object.keys uses the same order as a for..in loop, so in AS3 you could implement it the same way:
function getKeys(object:Object):Array {
var keys:Array = [];
for(var key in object){
keys.push(key);
}
return keys;
}
Note, though, that the enumerable order of keys on an object at runtime is not necessarily the same as you've written it in code.

Related

Comparing Original Array of Dom Elements with Sort Array of Dom Elements and check if they are different

I have a structure of dynamic DOM elements that I'm continuously evaluating with a for loop and a setInterval. While in that interval I sort the array and then change the dom with a JQuery Sort function in order to order my DOM structure on the fly.
The thing is I only want to change the DOM if the sort function is actually changing the order of elements (usually this happens when a new DOM element comes into the structure dynamically), if the sort function runs again over an already sortered array I don't want to do anything with the dom.
I have found A LOT of ways to compare if Arrays are equal but my case is special since i don't really care about the arrays elements / content but I really need to check if those elements are not in the same order so i can change the dom.
setInterval(function () {
//Incoming Chat Structure Variables
var $incomingChatsTable, $incomingChatsRows, $incomingChatTags
$incomingChatsTable= $("div[__jx__id*='incoming_list__list_content_container']")
$incomingChatsRowsContainer=$("div[__jx__id='___$_194__visitor_list__incoming_list__list__content']")
$incomingChatsRows = $("div[class*='renderers_Incoming']")
$incomingChatTags = $( "div[__jx__id*='incoming_list__list__content'] div[class*='renderers_Incoming'] .visitorlist_tags .jx_ui_html_span:last-child .tag").toArray()
$popupTrigger = $("div[jx\\:list\\:rowid]")
//Assigning Priorities Function
function assignPriority(arrayParent) {
for ( var i=0; i <= arrayParent.length; i++) {
var actualRow = $(arrayParent[i])
var minutesInQueue = $(actualRow).find('.time_cell').text().substr(0,2)
var priorityVal = parseInt(minutesInQueue)
var actualRowTags = $( actualRow ).find('.tag').toArray()
$(actualRow).addClass('priorityRow')
for (var k=0; k <= actualRowTags.length; k++) {
let normalHolderTag = $(actualRowTags[k]).text().toLowerCase()
if (normalHolderTag === 'vip') {
priorityVal += 30
$(actualRow).attr('data-priority', priorityVal)
} else if ( normalHolderTag === 'rg' ) {
priorityVal += 20
$(actualRow).attr('data-priority', priorityVal)
} else if ( normalHolderTag === 'accountclosure' ) {
priorityVal += 10
$(actualRow).attr('data-priority', priorityVal)
} else {
$(actualRow).attr('data-priority', priorityVal)
}
//$(actualRow).find('.numbers_cell').text(priorityVal)
}
}
}
//Sorting Incoming Chats By Priority
function orderByPriority(container) {
myArray = container.find('.priorityRow')
var changed = false
myArray.sort(function(a,b){
contentA = parseInt( $(a).data('priority') )
contentB = parseInt( $(b).data('priority') )
if ( (contentB - contentA) * ( myArray.indexOf(b) - myArray.indexOf(a) ) > 0 ){
changed = true
}
return (contentB - contentA)
})
if(changed) {
$(sortedArray).prependTo( container )
} else{
console.log('No need To Sort')
}
}
setInterval(function () {
assignPriority( $incomingChatsRows )
orderByPriority( $incomingChatsRowsContainer )
}, 500)
}, 1000)
UPDATE:
myArray is now a global variable, I have added an IF statement evaluating the sort function result and multiplying that result by the a, b indexes. If that's greater than 0 then i change the value of my "changed" variable to "true" BUT I'm getting a "myArray.indexOf is not a function" error.
You can add a line of code in your orderByPriority sort function which sets a variable to true only if it actually changes something:
function orderByPriority(container) {
var myArray = container.find('.priorityRow')
var changed = false
myArray.sort(function(a,b){
contentA = parseInt( $(a).data('priority') )
contentB = parseInt( $(b).data('priority') )
if((contentB - contentA)*(myArray.index(b)-myArray.index(a))>0){
//check if these have the same sign, i.e. something has changed
changed = true;
}
return (contentB - contentA)
})
if(changed){}//do something to modify DOM
}
The sort function has three possible outputs which will determine whether the two inputs need to be sorted:
Greater than 0: sort a to an index greater than b
Less than 0: sort b to an index greater than a
Equal to 0: don't change the order
The possible conditions which will result in a change being made are therefore:
Output greater than 0 and the index of a is currently less than the index of b
Output less than 0 and the index of a is currently greater than the index of b
We can represent the difference between the two indexes as index(b)-index(a). If the index of a is currently less than the index of b, this value will be positive. Otherwise, the value will be negative.
We can thus see that the above conditions are really saying:
if output and index(b)-index(a) have the same sign, something needs to be changed.
We can check if they have the same sign by multiplying them by eachother and testing if the result is greater than 0. This means that something has changed, so inside the if condition we set changed to true

Unable to add new key value into an existing JSON Array with JSON objects

Here is what I have tried.
I have tried dot notation and quotes. None of them seem to work. What exactly could be the problem?
var clientsList;
Client.find({}, function(err, clients) {
clientsList = clients;
// I have 10 clients in the loop
for (var j = 0; j < clientsList.length; j++) {
var x = clientsList[j];
x.count = "20";
//x["count"] = "20";
console.log(x);
}
});
Existing Client object
{"name":"abcd", "email":"abc#gmail.com"}
I'm unable to add the count key value pair into the client object. What could be the problem?
I suspect the object you're being given by Client.find has extensions prevented (it's sealed or frozen).
You can create a new object with the original's own, enumerable properties plus your count property using ES2018 spread notation:
x = {...x, count: "20"};
...or ES2015's Object.assign:
x = Object.assign({}, x, {count: "20"});
If the array is also sealed or frozen, you can copy it and its objects like this:
clientList = clients.map(client => {
return {...client, count: "20"}; // Or with `Object.assign`
});
or even with the concise form of the arrow function:
clientList = clients.map(client => ({...client, count: "20"}));
Side note: This pattern:
var clientsList;
Client.find({}, function(err, clients) {
clientsList = clients;
// ...
});
...often suggests that you intend to use clientsList in code following the Client.find call and expect it to have the result from that call's callback. See this question's answers for why, if you're doing that, it doesn't work.

couchbase Reduce gives not wanted result

I have a map function that returns a result like this :
{"total_rows":100995,"rows":[
{"id":"00001_372792","key":["00001","CADENCIER",0],"value":-0.1961035657664066},
{"id":"00001_372792","key":["00001","CADENCIER",0],"value":-0.1961035657664066},
{"id":"00001_386302","key":["00001","CADENCIER",0],"value":0.6934708647727543},
{"id":"00001_386302","key":["00001","CADENCIER",0],"value":0.6934708647727543},
{"id":"00001_386963","key":["00001","CADENCIER",0],"value":0.6922628824612621},
{"id":"00001_386963","key":["00001","CADENCIER",0],"value":0.6922628824612621},
{"id":"00001_387089","key":["00001","CADENCIER",0],"value":0.6919048724571887},
{"id":"00001_387089","key":["00001","CADENCIER",0],"value":0.6919048724571887},
{"id":"00001_387091","key":["00001","CADENCIER",0],"value":0.6919048724571887},
{"id":"00001_387091","key":["00001","CADENCIER",0],"value":0.6919048724571887},
{"id":"00001_387099","key":["00001","CADENCIER",0],"value":0.6921140124188077},
{"id":"00001_387099","key":["00001","CADENCIER",0],"value":0.6921140124188077},
{"id":"00001_387105","key":["00001","CADENCIER",0],"value":0.6921140124188077},
{"id":"00001_387105","key":["00001","CADENCIER",0],"value":0.6921140124188077},
{"id":"00001_387193","key":["00001","CADENCIER",0],"value":0.6936603115840247},
{"id":"00001_387193","key":["00001","CADENCIER",0],"value":0.6936603115840247},
{"id":"00001_387848","key":["00001","CADENCIER",1],"value":-0.29332158594360835},
{"id":"00001_387848","key":["00001","CADENCIER",1],"value":-0.29332158594360835},
{"id":"00001_388313","key":["00001","CADENCIER",1],"value":-0.0461553701861542},
{"id":"00001_388313","key":["00001","CADENCIER",1],"value":-0.0461553701861542},
{"id":"00001_388806","key":["00001","CADENCIER",1],"value":-0.04833054041013961},
{"id":"00001_388806","key":["00001","CADENCIER",1],"value":-0.04833054041013961},
{"id":"00001_388897","key":["00001","CADENCIER",1],"value":-0.25761199232338083},
{"id":"00001_388897","key":["00001","CADENCIER",1],"value":-0.25761199232338083},
{"id":"00001_435016","key":["00001","CADENCIER",1],"value":-0.037149057843773745},
{"id":"00001_435016","key":["00001","CADENCIER",1],"value":-0.037149057843773745}
...
]}
I want to reduce to group by key and return the count of values of each key as well as some other calculation on the values.
I did this:
function (key, values, rereduce) {
var result = {};
var ecartsSum;
for(var i = 0; i < values.length; i++) {
ecartsSum =+ values[i];
}
result.productsNumber = values.length;
result.index = 100 + (Math.tan(ecartsSum/values.length)) * 100
return result;
}
When I request the view using the key ["00001","CADENCIER",0]
I get this result :
{
"productsNumber": 3,
"index": null
}
which is not at all the result I was expecting.
PS: I use these options to select :
connection_timeout=600000000&full_set=true&group=true&inclusive_end=true&key=%5B%2200001%22,%22CADENCIER%22,0%5D&limit=6&reduce=true&skip=0&stale=false
Not all values for a given key are passed to the reduce function at one time. The MapReduce view will work on subsets of the data, reducing each subset and combining them using the same reduce function until all values have been processed.
You'll need to use the rereduce argument so the function can reduce the output from previous calls to itself.
From the Re-reduce Argument documentation:
In order to handle incremental map/reduce functionality (i.e. updating an existing view), each function must also be able to handle and consume the functions own output. This is because in an incremental situation, the function must be handle both the new records, and previously computed reductions.
Try something like this example from the documentation:
function(key, values, rereduce) {
var result = {total: 0, count: 0};
for(i=0; i < values.length; i++) {
if(rereduce) {
result.total = result.total + values[i].total;
result.count = result.count + values[i].count;
} else {
result.total = sum(values);
result.count = values.length;
}
}
return(result);
}

Javascript: Using reviver function, I seem can't get to alter all the keys, while concating the numbers

I just want to change all the keys in batchesX. But I can't seem to alter all keys, because of concat. This is what I learned from post.
Please advise how I can change all keys with numbers.
var batchesX = '[{"batch":"0010002033"},{"batch":"0010001917"},{"batch":"0000020026"},{"batch":"0000017734"},'+
'{"batch":"0000015376"},{"batch":"0000014442"},{"batch":"0000014434"},{"batch":"0000014426"},'+
'{"batch":"0000013280"},{"batch":"0000012078"},{"batch":"0000012075"},{"batch":"0000012072"},'+
'{"batch":"0000011530"},{"batch":"0000011527"},{"batch":"0000011342"},{"batch":"0000010989"},'+
'{"batch":"0000010477"},{"batch":"0000008097"},{"batch":"0000007474"},{"batch":"0000006989"},'+
'{"batch":"0000004801"},{"batch":"0000003566"},{"batch":"0000003565"},{"batch":"0000001392"},'+
'{"batch":"0000001391"},{"batch":"0000000356"},{"batch":"0000"},{"batch":"000"},{"batch":""},'+
'{"batch":null}]'; // 30 elements
//in JSON text
var batchi = "batch";
var obj_batchesY = JSON.parse(batchesX);
console.debug(obj_batchesY);
var obj_batchesYlength = obj_batchesY.length;
console.debug(obj_batchesYlength);
var obj_batchesX = JSON.parse(batchesX,
function(k,v)
{
for(var i=1; i <= obj_batchesYlength; i++ )
{
if(k=="batch")
{
this.batchi.concat(string(i)) = v;
}
else
return v;
}
}
);
console.debug(obj_batchesX);
Is the code too long winded?
Many thanks in advance.
Clement
The return value of the reviver function only replaces values. If you need to replace keys, then use stringify and replace before the parse call, like this:
JSON.parse(JSON.stringify({"alpha":"zulu"}).replace('"alpha":','"omega":'))
Here is how to replace all numeric keys:
function newkey()
{
return Number(Math.random() * 100).toPrecision(2) + RegExp.$1
}
//Stringify JSON
var foo = JSON.stringify({"123":"ashanga", "12":"bantu"});
//Replace each key with a random number without replacing the ": delimiter
var bar = foo.replace(/\d+("?:)/g, newkey)
//Parse resulting string
var baz = JSON.parse(bar);
Make sure each replaced key is unique, since duplicate keys will be removed by the parse method.

How to browse keys of an object

I'm looking to get/display the key name of an object in AS3.
I have for example :
var obj:Object = {key:"value"};
Here I try to display "key" (not its value).
The goal is to be able to merge two objects together.
Any idea ?
Thanks !
To get at the keys of an object you need to loop over them:
for (var key:String in obj) {
trace("key:", key, "value:", obj[key]);
}
Thus, merging obj1 and obj2 (with anything from the second overwriting the first) would look like this:
var merged:Object = {};
var key:String = "";
for (key in obj1) {
merged[key] = obj1[key];
}
for (key in obj2) {
merged[key] = obj2[key];
}