Second Greatest Value Displaying As "undefined" - javascript

All variables below are integer values of a range input slider. The code below should log the second greatest value of the sliders to the console. For example, if sliderA = 2, sliderB = 3, and sliderC = 4, the number 3 should be logged to the console. Instead, I'm getting the output "undefined". The code below works when the function is called with integers instead of variables. Does anyone know how to solve this problem?
var AS = Number(getNumber("animalsSlide"));
var MS = Number(getNumber("mathSlide"));
var CS = Number(getNumber("cookingSlide"));
var BS = Number(getNumber("biologySlide"));
var PS = Number(getNumber("performingSlide"));
var WS = Number(getNumber("writingSlide"));
var CAS = Number(getNumber("creativeSlide"));
var IS = Number(getNumber("inventingSlide"));
function secondGreatest(arr_num) {
arr_num.sort(function(x,y) {
return x-y;
});
var uniqa = [arr_num[0]];
var result = [];
for(var j=1; j < arr_num.length; j++) {
if(arr_num[j-1] !== arr_num[j]) {
uniqa.push(arr_num[j]);
}
}
result.push(uniqa[uniqa.length-2]);
return result.join(',');
}
console.log(secondGreatest([AS,MS,CS,BS,PS,WS,CAS,IS]));

You could search for the second large value of the sorted array.
const
values = [5, 5, 5, 4, 4, 3, 2, 1],
second = values.find(((last, count = 0) => value => {
if (last !== value) {
count++;
last = value;
}
return count === 2;
})());
console.log(second);

since it works with integers and not strings, I assume the problem is with the getNumber function.
do you have code there that finds the slider by id?
something like this:
let getNumber = (sliderId) => {
return +document.getElementById(sliderId).value;
}
since the name of the function is getNumber it's easy to assume it returns a number and not a string, so that's what I did here.. and then you won't need to parse to number outside
var AS = getNumber("animalsSlide");
var MS = getNumber("mathSlide");
var CS = getNumber("cookingSlide");
var BS = getNumber("biologySlide");
var PS = getNumber("performingSlide");
var WS = getNumber("writingSlide");
var CAS = getNumber("creativeSlide");
var IS = getNumber("inventingSlide");

Related

Iterating over an object in a Google Apps script and printing to Google Sheets

I'm having trouble printing more than one row to my google sheet with this loop.
The first row appends fine, but I want the function to append all objects from the data var.
The data object is properly pulling from Firebase when I verify with a Logger.
var firebaseUrl = "https://test.firebaseio.com/alerts";
var secret = "sssssssssssssssssssss";
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl, secret);
var data = base.getData();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("feed");
var selection = sheet.getActiveRange();
var range = sheet.getActiveRange();
var values = range.getValues();
var columns = selection.getNumColumns();
var rows = selection.getNumRows();
var num = 2;
function writeToSheets() {
for(var i in data) {
var values = [
[ data[i].id, data[i].two, data[i].three, data[i].four ]
];
var keys = Object.keys(values[0]);
var sheetRow = [];
var entryKeys;
for (j in keys) {
sheetRow = [];
entryKeys = Object.keys(values[keys[j]])
for (k in entryKeys) {
sheetRow.push(values[keys[j]][entryKeys[k]]);
}
sheet.appendRow(sheetRow);
}
}
}
I've just tried this code (assuming that I guessed the data structure correctly):
function myFunction() {
var data = [
{'id': 1, 'two': 'test2', 'three': 'test3', 'four': 'test4'},
{'id': 2, 'two': 'test2-2', 'three': 'test3-2', 'four': 'test4-2'}
]
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("feed");
var selection = sheet.getActiveRange();
var range = sheet.getActiveRange();
var values = range.getValues();
var columns = selection.getNumColumns();
var rows = selection.getNumRows();
var num = 2;
function writeToSheets() {
for(var i in data) {
var values = [
[ data[i].id, data[i].two, data[i].three, data[i].four ]
];
var keys = Object.keys(values[0]);
var sheetRow = [];
var entryKeys;
for (j in keys) {
sheetRow = [];
entryKeys = Object.keys(values[keys[j]])
for (k in entryKeys) {
sheetRow.push(values[keys[j]][entryKeys[k]]);
}
sheet.appendRow(sheetRow);
}
}
}
writeToSheets();
}
When I run it, it fails after printing the first line with an error TypeError: Expected argument of type object, but instead had type undefined. (line 26, file "Code").
And it is easy to see what exactly happens if you run it in debug mode:
You have values array with one element (line 18)
The var keys = Object.keys(values[0]); becomes [0,1,2,3] (we have 4 values inside the first element of values array)
Then, having j from 0 to 3 we get entryKeys = Object.keys(values[keys[j])
When j = 0, values[keys[j]] = values[0] - we get the first element from values
When j = 1, values[keys[j]] = values[1] - here we fail, because there is only 1 element in values
I am not really sure what you are trying to do here with all these keys, but if you just want to print the data, it can be done simpler:
function writeToSheets() {
for(var i in data) {
var item = data[i];
sheetRow = [];
for (key in item) {
sheetRow.push(item[key]);
}
sheet.appendRow(sheetRow);
}
}

Lazy.js based fibonacci to map Bacon.js interval?

I have a code to generate fib sequences with lazy.js
var fibF = function()
{
var seq = []; //build sequence array in this closure
var f = function(n)
{
var val;
if (n <= 1)
{
val = 1; // as the Fib definition in Math
}
else
{
val = seq[n - 2] + seq[n - 1]; // as the Fib definition in Math
}
seq[n] = val;
return val;
};
return f;
}();
var fibSequence = _.generate(fibF);
/* just for test
var fib_1000 =
fibSequence
.take(1000) 
.toArray(); 
console.log(fib_1000);
//[ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55,...........,4.346655768693743e+208 ]
*/
At the same time, I have a code of timer with Bacon.js
var B = require('baconjs');
var timeSequence = B
.interval(1000); //every second
timeSequence
.onValue(function()
{
console.log(require('moment')().format('MMMM Do YYYY, h:mm:ss'));
// print timestamps every second
});
Then,
I want to map the the fibSequence onto timeSequence such as
var mySequence = fibSequence.map(timeSequence);
or
var mySequence = timeSequence.map(fibSequence);
Is it possible?
If so, please show me the way.
Any workaround solution is welcome.
Thanks.
EDIT working code:
//to simplify use Natrual, instead of Fib
var _ = require('lazy.js');
var __ = require('baconjs');
var natural = function(n)
{
return n;
};
var _natural = _.generate(natural); //natural numbers
var __timer = __.interval(1000); //every second
var map_to__ = function(_seq, __seq)
{
var it = _seq.getIterator();
var sequence =
__seq
.map(function()
{
it.moveNext();
return it.current();
});
return sequence;
};
var __mappedTimer = map_to__(_natural, __timer);
__mappedTimer
.onValue(function(x)
{
console.log(x); // print every second
});
I'm not sure whether this is the intended use of iterators, but it should work:
var it = fibSequence.getIterator()
var mySequence = timeSequence.map(function() {
return it.moveNext() && it.current();
});

Create an array [n,[v,..,z]] from a list of key-value pairs

I have this input sample:
var c1 = "s_A_3";
var c2 = "s_B_10";
var c3 = "s_B_9";
var c4 = "s_C_18";
var c5 = "s_C_19";
var c6 = "s_C_20";
Which can easily be concatenated to:
var keypairs = ["A_3","B_10","B_9","C_18","C_19","C_20"];
And I want to convert this to a multidimensional array like this:
var groupArray = [["A",[3]],["B",[10,9]],["C",[18,19,20]]];
It's like a kind of card-sorting. How can I achieve this?
Maybe something like this:
function makeGroups(arr) {
var result = [], prev;
for(var i = 0; i < arr.length; i++) {
var x = arr[i].split("_");
if (prev !== x[0]) {
prev = x[0];
result.push([prev, []]);
}
result[result.length - 1][1].push(x[1]); // or .push(parseInt(x[1], 10))
}
return result;
}
var keypairs = ["A_3","B_10","B_9","C_18","C_19","C_20"];
console.log(makeGroups(keypairs));
// [["A",["3"]],["B",["10","9"]],["C",["18","19","20"]]]
Demonstration
The above method assumes the groups will be contiguous (e.g. all B_ elements appear together). In case your input may be out of order, you can tweak this algorithm to still group all elements together regardless of where they appear in the input:
function makeGroups(arr) {
var result = [], keys = {};
for(var i = 0; i < arr.length; i++) {
var x = arr[i].split("_");
if (!(x[0] in keys)) {
keys[x[0]] = [];
result.push([x[0], keys[x[0]]]);
}
keys[x[0]].push(x[1]); // or .push(parseInt(x[1], 10))
}
return result;
}
var keypairs = ["A_3","B_10","C_18","C_19","C_20","B_9"];
console.log(makeGroups(keypairs));
// [["A",["3"]],["B",["10","9"]],["C",["18","19","20"]]]
Demonstration
When you need to mention "key value pairs" in a JS program, it's usually most appropriate to use... key value pairs =D.
function solution(input) {
var kvp = {},
result = [];
input.forEach(function (el) {
var cut = el.split("_"),
alpha = cut[0],
numeric = cut[1],
elsWithSameAlpha = kvp[alpha] = kvp[alpha] || [];
elsWithSameAlpha.push(numeric);
});
Object.keys(kvp).forEach(function (key) {
result.push([key, kvp[key]]);
});
return result;
}

Javascript merge 2 arrays and sum same key values

I have 2 array:
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
Want to get 1 merged array with the sum of corresponding keys;
var array1 = [[1,10],[2,10],[3,10],[4,10],[5,50],[6,50],[7,10],[8,10],[9,10]];
Both arrays have unique keys, but the corresponding keys needs to be summed.
I tried loops, concat, etc but can't get the result i need.
anybody done this before?
You can use .reduce() to pass along an object that tracks the found sets, and does the addition.
DEMO: http://jsfiddle.net/aUXLV/
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
var result =
array1.concat(array2)
.reduce(function(ob, ar) {
if (!(ar[0] in ob.nums)) {
ob.nums[ar[0]] = ar
ob.result.push(ar)
} else
ob.nums[ar[0]][1] += ar[1]
return ob
}, {nums:{}, result:[]}).result
If you need the result to be sorted, then add this to the end:
.sort(function(a,b) {
return a[0] - b[0];
})
This is one way to do it:
var sums = {}; // will keep a map of number => sum
// for each input array (insert as many as you like)
[array1, array2].forEach(function(array) {
//for each pair in that array
array.forEach(function(pair) {
// increase the appropriate sum
sums[pair[0]] = pair[1] + (sums[pair[0]] || 0);
});
});
// now transform the object sums back into an array of pairs
var results = [];
for(var key in sums) {
results.push([key, sums[key]]);
}
See it in action.
a short routine can be coded using [].map()
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
array1=array2.concat(array1).map(function(a){
var v=this[a[0]]=this[a[0]]||[a[0]];
v[1]=(v[1]||0)+a[1];
return this;
},[])[0].slice(1);
alert(JSON.stringify(array1));
//shows: [[1,10],[2,10],[3,10],[4,10],[5,50],[6,50],[7,10],[8,10],[9,10]]
i like how it's just 3 line of code, doesn't need any internal function calls like push() or sort() or even an if() statement.
Try this:
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
var res = [];
someReasonableName(array1, res);
someReasonableName(array2, res);
function someReasonableName(arr, res) {
var arrLen = arr.length
, i = 0
;
for(i; i < arrLen; i++) {
var ar = arr[i]
, index = ar[0]
, value = ar[1]
;
if(!res[index]) {
res[index] = [index, 0];
}
res[index][1] += value;
}
}
console.log(JSON.stringify(res, null, 2));
So, the result may have holes. Just like 0th index. Use the below function if you want to ensure there are no holes.
function compact(arr) {
var i = 0
, arrLen = arr.length
, res = []
;
for(i; i < arrLen; i++) {
var v = arr[i]
;
if(v) {
res[res.length] = v;
}
}
return res;
}
So, you can do:
var holesRemoved = compact(res);
And finally if you don't want the 0th elem of res. Do res.shift();
Disclaimer: I am not good with giving reasonable names.
The simple solution is like this.
function sumArrays(...arrays) {
const n = arrays.reduce((max, xs) => Math.max(max, xs.length), 0);
const result = Array.from({ length: n });
return result.map((_, i) => arrays.map(xs => xs[i] || 0).reduce((sum, x) => sum + x, 0));
}
console.log(...sumArrays([0, 1, 2], [1, 2, 3, 4], [1, 2])); // 2 5 5 4

How to get all possible combinations of multiple sets where order matters recursively

Given multiple sets of values. I want to find every combination (sorry I am using this term loosely but am not sure what the correct word is) of those values while preserving the order.
ie for
var set1 = ["a","1"];
var set2 = ["b","2"];
var set3 = ["c","3"];
the output should be
[a][b][c]
[a][b][3]
[a][2][c]
[a][2][3]
[1][b][c]
[1][b][3]
[1][2][c]
[1][2][3]
This provides the correct results, but I don't think this is a very good solution but just can't wrap my head around doing this recursively. The example is in Javascript but any language or insight is fine.
var set1 = ["a","1"];
var set2 = ["b","2"];
var set3 = ["c","3"];
var input = [set1, set2, set3];
var result = [];
for(var a=0;a<input[0].length;a++){
for(var i=0;i<input[1].length;i++){
for(var j=0;j<input[2].length;j++){
var output = [];
output.push(input[0][a]);
output.push(input[1][i]);
output.push(input[2][j]);
result.push(output);
console.log("["+input[0][a]+"]["+input[1][i]+"]["+input[2][j]+"]");
}
}
}
Sure, you can recursively explore the space like this:
function extend_set (base, sets) {
if(sets.length === 0) {
return console.log('found: '+base);
}
sets = sets.slice();
var choices = sets.shift();
for (var i = 0; i < choices.length; i += 1) {
var b2 = base.slice();
b2.push(choices[i]);
extend_set(b2, sets);
}
}
var set1 = ["a","1"];
var set2 = ["b","2"];
var set3 = ["c","3"];
var sets = [set1, set2, set3];
extend_set([], sets);

Categories