ColdFusion 8 ArrayFind Substitute - arrays

I have an array that has a structure of ImageID and Custnum.
I need to find a particular ImageID and retrieve the Custnum for it.
I’m using ColdFusion 8 which does not have an ArrayFind command.
How would I do this without looping through each item? Thanks.

Your question may be answered to a point here "Is there a function similar to ArrayFind from ColdFusion 9 in ColdFusion 8?" but I don't see any other way apart from looping.
You can always create and use an UDF but it would have to use looping.
Why exactly you don't want to use looping anyway? Do you have that many elements in the array? Just remember to use cfbreak after finding your element to stop going through the rest of the array.

Given your situation, I don't think arrayFind() would help you much anyhow, as to find something with arrayFind(), you need to know exactly what you're looking for anyhow. And whilst you know your ImageID, you don't know the Custnum associated with it (hence your underlying problem).
There's nothing native in CF which can help you here, but there's a UDF on CFLib - structFindKeyWithValue() which'll do the trick.
It's written for CF9, but is easily backported to CF8. The modified, CF8-friendly version - is in the example below:
<cfscript>
a = [
{ImageID=1, Custnum=1},
{ImageID=2, Custnum=2},
{ImageID=3, Custnum=3},
{ImageID=4, Custnum=4}
];
testStruct = {a=a};
result = structFindKeyWithValue(testStruct, "ImageID", 2, "ONE");
function structFindKeyWithValue(struct, key, value, scope){
var keyResult = false;
var valueResult = [];
var i = 0;
if (!isValid("regex", arguments.scope, "(?i)one|all")){
throw(type="InvalidArgumentException", message="Search scope #arguments.scope# must be ""one"" or ""all"".");
}
keyResult = structFindKey(struct, key, "all");
for (i=1; i <= arrayLen(keyResult); i++){
if (keyResult[i].value == value){
arrayAppend(valueResult, keyResult[i]);
if (scope == "one"){
break;
}
}
}
return valueResult;
}
</cfscript>
<cfdump var="#result#">
Note that because it's a stuct function, you need to wrap your data in a struct first. Other than that it's fairly straight fwd.

Related

Node fast way to find in array

I have a Problem.
My script was working fine and fast, when there was only like up to 5000 Objects in my Array.
Now there over 20.000 Objects and it runs slower and slower...
This is how i called it
for(var h in ItemsCases) {
if(itmID == ItemsCases[h].sku) {
With "for" for every object and check where the sku is my itmID, cause i dont want every ItemsCases. Only few of it each time.
But what is the fastest and best way to get the items with the sku i need out of it?
I think mine, is not the fastest...
I get multiple items now with that code
var skus = res.response.cases[x].skus;
for(var j in skus) {
var itmID = skus[j];
for(var h in ItemsCases) {
if(itmID == ItemsCases[h].sku) {
the skus is also an array
ItemsCases.find(item => item.sku === itmID) (or a for loop like yours, depending on the implementation) is the fastest you can do with an array (if you can have multiple items returned, use filter instead of find).
Use a Map or an object lookup if you need to be faster than that. It does need preparation and memory, but if you are searching a lot it may well be worth it. For example, using a Map:
// preparation of the lookup
const ItemsCasesLookup = new Map();
ItemsCases.forEach(item => {
const list = ItemsCasesLookup.get(item.sku);
if (list) {
list.push(item)
} else {
ItemsCasesLookup.set(item.sku, [item]);
}
});
then later you can get all items for the same sku like this:
ItemsCasesLookup.get(itmID);
A compromise (not more memory, but some speedup) can be achieved by pre-sorting your array, then using a binary search on it, which is much faster than linear search you have to do on an unprepared array.

appendRow from an array

If I have an array, [Joe, John, Adam, Sam, Bill, Bob] and I want to try to add this to a new row by doing SpreadsheetApp.getActive().getSheetByName('Sheet4').appendRow([array]); , what happens is that the entire list of names goes into 1 cell. Is there a way to break this up so they file away into the same row, but different columns? I need to continue using appendRow however.
I get this:
But I really want to have it look like this:
var my2DArrayFromRng = datasheet.getRange("A:A").getValues();
var a = my2DArrayFromRng.join().split(',').filter(Boolean);
var array = [];
for (d in a) {
array.push(a[d]);
}
SpreadsheetApp.getActive().getSheetByName('Sheet4').appendRow([array.toString()]);
You are converting your array to a string before you post it which is causing your issue.
Do not use the array.toString() method inside append row. Instead just append the array as it is.
SpreadsheetApp.getActive().getSheetByName('Sheet4').appendRow(array);

Convert Parse.com json array into Array with swift

Can someone please help me with this. I saved my data into Parse.com into column with type array (example: ["11:30","12:45,"13:02"], just some list of some times as string). I have tried to get this data with swift:
var take: NSMutableArray!
var query = PFQuery(className: "test")
query.getObjectInBackgroundWithId("QZ6Y8Oljc5"){
(testData: PFObject!, error: NSError!) -> Void in
if (error == nil){
take = testData["workday"]
println(take)
}
else{
println(error)
}
}
the problem is that i get only json array type:
(
"11:30",
"12:45,
"13:02"
)
How can I convert it into NSArray so it could be like:
var myArray = ["11:30","12:45,"13:02"]
Thank you for any suggestions because I tried every method I found here, but without any results.
The problem with JSON data is that it is it's own array that has to be sifted and groomed. normally people would end up using huge nested IF statements which ends up looking messy. Luckily, someone created a code that sifts through JSON data and gives you back usable types (Int, Arrays, Strings) by use of a massive switch table.
https://github.com/SwiftyJSON/SwiftyJSON
Look it up, it should help. Once you have it implemented you can call it by typing..
let json = JSON(Data : JSONData)
then to sift through, you use substrings.. (depending on the data, you match it with a string or int)
let firstIndex = json["workday"]
//Int
let firstIndexOfWorkDay = json["workday"][0]
//String
let firstIndexOfWorkDay = json["workday"]["time"]
and so on... however, you will need to cast it once you singled out the data
let firstIndexOfWorkDay = json["workday"][0].valueOfFloat
//printing it would give 11:30
although personally I use ".description" .. since sometimes when I sift through all the array, its a mix of types.
let firstIndexOfWorkDay = json["workday"][0].description
println(firstIndexOfWorkDay)
//would literally give "11:30" including the quotation marks
then I use string methods to trim the quotations then cast it to whatever type I need. But it's up to your creativity once you figure out how it works

Sorted array: how to get position before and after using name? as3

I have been working on a project and Stack Overflow has helped me with a few problems so far, so I am very thankful!
My question is this:
I have an array like this:
var records:Object = {};
var arr:Array = [
records["nh"] = { medinc:66303, statename:"New Hampshire"},
records["ct"] = { medinc:65958, statename:"Connecticut"},
records["nj"] = { medinc:65173, statename:"New Jersey"},
records["md"] = { medinc:64596, statename:"Maryland"},
etc... for all 50 states. And then I have the array sorted reverse numerically (descending) like this:
arr.sortOn("medinc", Array.NUMERIC);
arr.reverse();
Can I call the name of the record (i.e. "nj" for new jersey) and then get the value from the numeric position above and below the record in the array?
Basically, medinc is medium income of US states, and I am trying to show a ranking system... a user would click Texas for example, and it would show the medinc value for Texas, along with the state the ranks one position below and the state that ranks one position above in the array.
Thanks for your help!
If you know the object, you can use the array.indexOf().
var index:int = records.indexOf(records["nj"]);
var above:Object;
var below:Object;
if(index + 1 < records.length){ //make sure your not already at the top
above = records[index+1];
}
if(index > 0){ //make sure your not already at the bottom
below = records[index-1];
}
I think this is the answer based on my understanding of your data.
var index:int = arr.indexOf(records["nh"]);
That will get you the index of the record that was clicked on and then for find the ones below and above just:
var clickedRecord:Object = arr[index]
var higherRecord:Object = arr[index++]
var lowerRecord:Object = arr[index--]
Hope that answers your question
Do you really need records to be hash?
If no, you can simply move key to record field and change records to simple array:
var records: Array = new Array();
records.push({ short: "nh", medinc:66303, statename:"New Hampshire"}),
records.push({ short: "ct", medinc:65958, statename:"Connecticut"}),
....
This gives you opportunity to create class for State, change Array to Vector and make all of this type-safe, what is always good.
If you really need those keys, you can add objects like above (with "short" field) in the same way you are doing it now (maybe using some helper function which will help to avoid typing shortname twice, like addState(records, data) { records[data.short] = data }).
Finally, you can also keep those records in two objects (or an object and an array or whatever you need). This will not be expensive, if you will create state object once and keep references in array/object/vector. It would be nice idea if you need states sorted on different keys often.
This is not really a good way to have your data set up - too much typing (you are repeating "records", "medinc", "statename" over and over again, while you definitely could've avoided it, for example:
var records:Array = [];
var states:Array = ["nh", "ct", "nj" ... ];
var statenames:Array = ["New Hampshire", "Connecticut", "New Jersey" ... ];
var medincs:Array = [66303, 65958, 65173 ... ];
var hash:Object = { };
function addState(state:String, medinc:int, statename:String, hash:Object):Object
{
return hash[state] = { medinc: medinc, statename: statename };
}
for (var i:int; i < 50; i++)
{
records[i] = addState(states[i], medincs[i], statenames[i], hash);
}
While you have done it already the way you did, that's not essential, but this could've saved you some keystrokes, if you haven't...
Now, onto your search problem - first of all, true, it would be worth to sort the array before you search, but if you need to search an array by the value of the parameter it was sorted on, there is a better algorithm for that. That is, if given the data in your example, your specific task was to find out in what state the income is 65958, then, knowing that array is sorted on income you could employ binary search.
Now, for the example with 50 states the difference will not be noticeable, unless you do it some hundreds of thousands times per second, but in general, the binary search would be the way to go.
If the article in Wiki looks too long to read ;) the idea behind the binary search is that at first you guess that the searched value is exactly in the middle of the array - you try that assumption and if you guessed correct, return the index you just found, else - you select the interval containing the searched value (either one half of the array remaining) and do so until you either find the value, or check the same index - which would mean that the value is not found). This reduces asymptotic complexity of the algorithm from O(n) to O(log n).
Now, if your goal was to find the correspondence between the income and the state, but it wasn't important how that scales with other states (i.e. the index in the array is not important), you could have another hash table, where the income would be the key, and the state information object would be the value, using my example above:
function addState(state:String, medinc:int, statename:String,
hash:Object, incomeHash:Object):Object
{
return incomeHash[medinc] =
hash[state] = { medinc: medinc, statename: statename };
}
Then incomeHash[medinc] would give you the state by income in O(1) time.

Is there a way to convert a struct into an array without using a loop?

I'm curious, is there another way to convert a struct into an array in Coldfusion without looping over it? I know it can be done this way if we use a for in loop:
local.array = [];
for (local.value in local.struct)
{
arrayAppend(local.array, local.value);
}
Does StructKeyArray suit your requirements?
Description
Finds the keys in a ColdFusion
structure.
If you are trying to maintain order in your structure you could always use a Java LinkedHashMap like so:
cfmlLinkedMap = createObject("Java", "java.util.LinkedHashMap").init();
cfmlLinkedMap["a"] = "Apple";
cfmlLinkedMap["b"] = "Banana";
cfmlLinkedMap["c"] = "Carrot";
for(key in cfmlLinkedMap){
writedump(cfmlLinkedMap[key]);
}
You could also do the same thing in a more "java" way not sure why you'd want to but its always an option:
//no need to init
linkedMap = createObject("Java", "java.util.LinkedHashMap");
//java way
linkedMap.put("d","Dragonfruit");
linkedMap.put("e","Eggplant");
linkedMap.put("f","Fig");
//loop through values
iterator = linkedMap.entrySet().iterator();
while(iterator.hasNext()){
writedump(iterator.next().value);
}
//or
//loop through keys
iterator = linkedMap.keySet().iterator();
while(iterator.hasNext()){
writedump(linkedMap.get(iterator.next()));
}
Just remember that the keys are case SeNsItIvE!
In Coldfusion 10 or Railo 4, if you want an array of values (instead of keys), you can use the Underscore.cfc library like so:
_ = new Underscore();// instantiate the library
valueArray = _.toArray({first: 'one', second: 'two'});// returns: ['one','two']
Note: Coldfusion structures are unordered, so you are not guaranteed to have any specific order for the values in the resulting array.
(Disclaimer: I wrote Underscore.cfc)

Resources