Summarizing a javascript array of strings - javascript

I have a variable length array of strings declared in javascript that contains Dungeons and Dragons class names. An example of this is below:
var class_names = new Array("Wizard", "Wizard", "Wizard", "Sorcerer",
"Sorcerer", "Ultimate Magus");
In my HTML, I use the javascript window.onload function to set a variety of variables from the javascript file to build the content of the page being displayed locally.
For things like name, this is easy:
document.getElementById('charname').innerHTML = name[0];
But for the class info, I don't want to just pump out a massive string of class names, I want it condensed down. Using the example 'class_names' above, I want to end up with a string that looks like this:
"Wizard 3, Sorcerer 2, Ultimate Magus 1"
i.e. the number after each class name should be the number of repetitions found in the array.
Anyone have an idea how to make this happen on the fly, so when I alter the javascript file to add more class data to class_names, it is displayed appropriately on my HTML page?
Thanks in advance for any help I get on this pet project (namely creating a HTML page for each character in my campaign that can be printed out as a character sheet....it's far better than manually writing a page for each character, or handwriting it on vanilla sheets).

It's easy enough, just loop through the array and count repetitions.
var l = class_names.length, i, tmp = {}, ret = [];
for( i=0; i<l; i++) {
if( !tmp[class_names[i]]) tmp[class_names[i]] = 0;
tmp[class_names[i]]++;
}
for( i in tmp) {
if( tmp.hasOwnProperty(i)) {
ret.push(i+" "+tmp[i]);
}
}
// output is ret.join(", ");

I think there are many ways to solve your problem...
Possibility A:
If you don't know if the classes are appearing in the right order, try to sort your Array first to ensure that they are grouped properly.
Iterate over the array and count the repetitions, i.e. increase your counter if
lastElement === class_names[i]
and append the result for the last class name to the result string and set the counter back to 1 otherwise.
Possibility B:
Store your Array directly as ["Wizard", 3, "Sorcerer", 2, ...] - this is possible since JS does not require arrays to contain the same type of element at each position.
Possibility C:
Use a different structure, e.g. using objects:
var class_names = [{name: "Wizard", level: 3}, {name: "Sorcerer", level: 2}, ...]

Related

Aggregate values in a javascript grouped object based on conditions

I am using IE 11.
I have an object array that is grouped using the lodash library. I want to be able to query the object and based on certain conditions come up with sums/counts. So for example, I have this object array.
I would like to have the result seen below but in an object like the image above
As you can see, each company in the group should have certain values based on the following criteria
How many times does 'company x' have a Total Count >3?
How many times does 'company x' have expectingFunding eq ‘Yes’>
How many times does 'company x' have fundedOnIKNS eq ‘No’?
I've tried quite a bit in the last couple of days but not success. I first declared 2 arrays so I can capture the unique values of company name and program. I also created an object to update when conditions were met. The only successful thing I was able to get was to keep it in an grouped object. All the values in the new object were wrong.
Here's an excerpt of the code:
const companiesSummary = {};
for (const company of Object.keys(myData)) {
companiesSummary[company] = {
totalCount: 0,
expectedFunding: 0,
IKNSFunding: 0,
};
for (const { TotalCount, expectedFunding, fundedOnIKNS } of myData[company]) {
companiesSummary[company].totalCount += TotalCount;
companiesSummary[company].expectedFunding += expectedFunding === "Yes";
companiesSummary[company].fundedOnIKNS += fundedOnIKNS === "Yes";
}
}
I get the error,
TypeError: myData[company] is not iterable
Here's a link to the pen
I would still like the result to be in an object array, so I can create an html table later. Any help would be much appreciated. Thank you!
Your code isn't working because you're taking myData, an array, accessing myData[company], an object (company is 0, 1, ...), and you can't iterate through an object with for...of. myData is definitely not the same object in your screenshot.
Your code excerpt might work if your myData object were the object in your screenshot.

Inserting values into multi-dimentional javascript array

I need to dynamically create a multidimensional javascript array that matches this layout:
array_answers[0][1]:"yes"
array_answers[1][2]:"no"
array_answers[2][2-subquestion]:"text input"
array_answers[3][8]:"yes"
array_answers[4][8-subquestion]:"text input"
The first "[ ]" defines what question it is on the page (out of totalInputs)
The second "[ ]" defines what question from the database this is (questions already in order to match the corresponding input)
and the information following is the input I am trying to add
I have attempted to the following with no luck.
for(var i = 0; i < totalInputs; i++) {
array_answers.push([i]);
array_answers[i].push([questions[i]]);
array_answers[i][0] = "yes, no, or other text";
}
The last line is where it falls apart. It would make sense to me that I should be able to use [0] to indicate that I want the first array to be given this value but with no avail.
I have also tried:
for(var i = 0; i < totalInputs; i++) {
array_answers.push([i]);
array_answers[i].push([questions[i]]);
array_answers[i][questions[i]] = "yes, no, or other text";
}
but this gives me lots of empty arrays for all the numbers from 0 to whatever the value of questions[i] is.
What am I missing or is there a simpler way to do this in jQuery while still conforming to the target layout?
If I understand you correctly, you are trying to store questions and prompts (maybe?) together in a multi dimensional array. let me suggest a different way that should work.
const array_answers = questions.map(q => [q, "yes, no, other text"]);
This may be what you want
I am still not 100% sure of what you need, but i thought I would write an answer with my assumptions, that I can update as the information improves.
The first "[ ]" defines what question it is on the page (out of
totalInputs)
This part looks like you are correct, and need to use an array. But an array is just a list of "things", in your case, questions. So where you have this line:
array_answers.push([i]);
I'm not sure it is doing what you are expecting. This is adding a new array item, which is in itself an array, that contains a single number. So if totalInputs is 3, then that first line will result in this structure:
array_answers= [[0],[1],[2]]
I think what you actually might intend here is to simply house an array of question details. Now by the complexity of your keys listed for the second dimension, it looks like an object would be more appropriate.
The second "[ ]" defines what question from the database this is
(questions already in order to match the corresponding input)
So lets go ahead and create a single question.
var question = {
anythingYouWant: 'here',
2: 'even numeric keys'
}
// you can access the values in these ways
console.log(question.anythingYouWant)
console.log(question[2])
console.log(question['anythingYouWant'])
Now once you have a question object, you can then add it to your array_answers array with push.
array_answers.push(question).
If you have two identical questions like the one above, your array will look like this:
array_answers = [{
anythingYouWant: 'here',
2: 'even numeric keys'
},{
anythingYouWant: 'here',
2: 'even numeric keys'
}]
In order to access the questions within the array, you can simply use their index:
// access second question
var secondQuestion = array_answers[1]
You can read these links to learn more about objects & arrays

Javascript equivalent of VBS redim preserve

I'm trying to rewrite some old VBScript as Javascript for an ASP.NET application and there is one line I'm not sure how to translate, and I'm not even entirely positive what it's doing.
The application essentially allows the user to enter in a new employee number to add to the database and then assign it user permissions. Don't ask me why the code is such a mess, I didn't write it originally, I'm just trying to make it work in Chrome
here's the relevant code that i've managed to translate so far:
if(form1.txtEmpno.value != ""){
var oOption;
oOption = document.createElement("OPTION");
oOption.text=form1.txtEmpno.value;
oOption.value=form1.txtEmpno.value;
form1.lstActive.add (oOption);
oOption = document.createElement("OPTION");
oOption.text="";
oOption.value="";
form1.lstPerms.add (oOption);
redim preserve arrUsers(1,ubound(arrUsers,2)+1);
arrUsers(0,ubound(arrUsers,2)) = form1.txtEmpno.value;
arrUsers(1,ubound(arrUsers,2)) = "";
form1.txtEmpno.value = "";
oOption = null;
}
here's the line in question:
redim preserve arrUsers(1,ubound(arrUsers,2)+1);
MSDN defines ReDim [Preserve] varname(subscripts) as:
The ReDim statement is used to size or resize a dynamic array that has already been formally declared using a Private, Public, or Dim statement with empty parentheses (without dimension subscripts). You can use the ReDim statement repeatedly to change the number of elements and dimensions in an array.
If you use the Preserve keyword, you can resize only the last array dimension, and you can't change the number of dimensions at all. For example, if your array has only one dimension, you can resize that dimension because it is the last and only dimension. However, if your array has two or more dimensions, you can change the size of only the last dimension and still preserve the contents of the array.
Arrays in JavaScript have different semantics to VBScript's arrays, especially in that they're actually closer to a vector than a true array, furthermore JavaScript does not provide for true N-dimensional arrays: instead you use staggered-arrays (arrays-within-arrays). Which means your VBScript cannot be syntactically converted to JavaScript.
Here's your relevant code in VBScript:
ReDim Preserve arrUsers(1,ubound(arrUsers,2)+1)
arrUsers(0,ubound(arrUsers,2)) = form1.txtEmpno.value
arrUsers(1,ubound(arrUsers,2)) = ""
We see that arrUsers is a 2-dimensional array. This will need to be converted into a staggered array, but you haven't posted the code that defines and initializes arrUsers, nor how it is used later on, so I can only work from making assumptions.
It looks to be adding 1 element to the last dimension, but the code only seems to use the extra space in the [1] subscript (i.e. it only wants the extra dimensional space for certain values of the 0th dimension instead of all values), which makes this simpler as you don't need to iterate over every 0th-dimension subscript.
JavaScript arrays have numerous function-properties that we'll use, in particular push: which appends an element to the end of an array (internally growing the buffer if necessary), and pop which removes the last (highest-indexed) element from an array (if an array is empty, it's a NOOP):
var arrUsers = [ [], [] ]; // empty, staggered 2-dimensional array
...
arrUsers[0].push( form1.txtEmpno.value );
arrUsers[1].pop();
Much simpler.
However, if this array is just part of some internal model to store and represent data then you should take advantage of JavaScript object-prototypes instead of using array indexes, as that makes the code self-describing, for example:
var User = function(empNo, name) {
this.employeeNumber = empNo;
this.name = name;
};
var users = [];
users.push( new User(1, "user 1") );
users.push( new User(23, "user 23") );
...
for(var i = 0; i < users.length; i++ ) {
alert( users[i].name );
}

Organise array push order

I've got an array. I push items multiple times into this array using a function. Below is an simplified version of the code.
var arr = [];
function pushItems(i){
//do something with i
var abc = "string"
arr.push(abc);
//do something with i
var xyz = "string"
arr.push(xyz);
}
Sometimes abc value is pushed before xyz. Sometimes xyz gets pushed before abc value. My question is how do I always have the abc value ahead of 'xyz' value?
So basically I need the array values to be [abc1, xyz1, abc2, xyz2, abc3, xyz3, ...] so on. How do I order the push accordingly?
This is wrong. According to the specification of this method:
The push() method adds one or more elements to the end of an array and
returns the new length of the array.
Please have a look here.
For a more formal approach please see the ECMAScript specification here.
The arguments are appended to the end of the array, in the order in
which they appear. The new length of the array is returned as the
result of the call.
Update
But even if the elements are added at the end of the array, I'm
looking a way of ordering my array.
You can use the sort function for this reason passing to it an appropriate function that will do the compare. For instance, let we have the following array
var array = [4,1,2,5,3];
and we want to order it in a descending order, we could do this like below:
var array = array.sort(function(a,b){ return b-a; });
Since you need your base64-strings to be in an arbitrary order in the array, sort them by an identifier you define.
var firstObj = {id: 0, base64: 'asdf'}
var secondObj = {id: 1, base64: 'qwer'}
var arr = []
// do stuff
// callback needs to have something along these lines:
function base64isLoaded(obj){
arr[obj.id] = obj.base64;
}
Now the 'front' image (as you gave this as example) can be given id: 0, so it ends up in the '0' spot of the array. I can't really help more without more information about how your code is structured.
EDIT: From your comment ("passing multiple items into pushItems"), I am going to assume that i (the argument) is an array and you iterate this array to transform each element into a base64 encoded string. You then want these encoded strings added to arr in the same order, correct?
easily done, simply make i an array of objects:
var i = [{source: 'abc'}, {source: 'xyz'}];
pushItems(i){
for(var c = 0; c < i.length; c++){
makeIntoBase64(i[c]);
}
}
makeIntoBase64(obj){
// this is whatever function that transforms it and takes a callback when it is done
transform(obj.source, function(result){ //pass the source to be encoded
//result should be base64 encoded string
obj.encoded = result;
});
}
after all this, the array i has objects with both .source and .encoded. If you need to know when ALL encoding is done, create a counter and add one to it in the transform callback, and check if counter === i.length every time. When it is, you know you have loaded all base64 strings and can run another function, adding these images to your catalogue or whatever else you need this for :)

How to dynamically update drop-down list options with values in a server-generated array

I have a web form with two drop-down boxes, and I'm looking for a way to dynamically update the options of the second box based on selections from the first.
The first box represents a data type, and the second box is a list of databases associated with the selected type.
I have the basic code running smoothly here:
var TypeA_DbSuffixList = ['Test1', 'Test2', 'Test3'];
var TypeB_DbSuffixList = ['TestA', 'TestB', 'TestC'];
function fill_dbSuffixList(){
document.getElementById("dbSuffixList").options.length = 0;
var suffixMenu = document.getElementById("dbSuffixList");
var dataFormat = document.getElementById("dataFormatType");
var suffixList = dataFormat.value + "dbSuffixList";
if (suffixList == 'TypeA_dbSuffixList') {
for(index in TypeA_dbSuffixList) {
suffixMenu.options[suffixMenu.options.length] = new Option(TypeA_dbSuffixList[index], index);
}
}
if (suffixList == 'TypeB_dbSuffixList') {
for(index in TypeB_dbSuffixList) {
suffixMenu.options[suffixMenu.options.length] = new Option(TypeB_dbSuffixList[index], index);
}
}
}
That code (activated whenever a selection is made in the dataType box) clears the existing list of options and repopulates the list based on the selected value of the "dataFormatType" box.
The problem that I face is that the actual lists of database tables are not hard coded and are instead generated with the following calls to the server to avoid repetitive editing of the page every time a new database is added:
var TypeA_dbSuffixList = ${TypeA_dbSuffixList};
var TypeB_dbSuffixList = ${TypeB_dbSuffixList};
These calls return the following code:
var TypeA_dbSuffixList = [Test1, Test2, Test3];
var TypeB_dbSuffixList = [TestA, TestB, TestC];
With the above code, the initial function treats each entry in the type arrays as an undefined variable, and nothing is ever written to the drop-down list.
If I were to add
var Test1 = "Apple";
var Test2 = "Orange";
var Test3 = "Grape";
prior to the "for" loop for TypeA, then selecting TypeA from the dataType drop-down list returns "Apple", "Orange", and "Grape" as the available databases for TypeA.
Visually, I see what needs to be changed. The [Test1, Test2, Test3] returns need to be ['Test1', 'Test2', 'Test3']. I'm just unsure exactly how to go about changing it, and have exhausted every web search I can think of.
Is there a way to either change the format of the returned arrays, or use the existing format and pass variable names as drop-down selections instead of using variable values?
Any help is greatly appreciated. I will continue to search for an answer on my own as well and will post it here should I find one.
I think the cleanest solution would be to change the code on the server-side to generate a proper JavaScript array of Strings, with the values enclosed in single or double quotes.
If that's not possible for some reason, and you want a pure-JavaScript solution, then I suggest you wrap the entire JSP/ASP/PHP variable (not sure what framework you're using) in double quotes, strip the string of brackets and spaces using a regex, and then split it into a string array using the comma as a delimiter.
So in your JavaScript, this:
var TypeA_dbSuffixList = ${TypeA_dbSuffixList};
would become this:
var TypeA_dbSuffixList = "${TypeA_dbSuffixList}".replace(/[\[\]\s]/g,"").split(",");
I think the best way to convert data in a server side language into something to be used in JavaScript is to JSON encode your objects.
I'm not sure what language your using on the server, but in PHP you can do the following
var arr = <?php echo json_encode( array ('abc', 'def', 'ghi') ); ?> ;
And your output will be
var arr = ['abc', 'def', 'ghi'] ;
This will make sure that strings with embedded new lines, tabs, quotes are properly escaped.
JSP
You said you're using JSP but the code you have looks more like velocity or free marker inside JSP. In JSP you could use the following, provided you download Gson
var TypeA_dbSuffixList = <%= new Gson().toJson(TypeA_dbSuffixList) %>;

Categories