Javascript pairwise comparison for difference between 6 variables - javascript

In javascript I am trying to automate the pairwise comparison of up to 6 integers in input boxes, comparing numbers as they are entered until 3 numbers are within 0.2 of one another. It is not necessary to enter all 6 values in order to have three numbers within 0.2 of one another, therefore some of the 6 potential input values may remain null or 0, but which should be ignored in the comparisons.
I have loaded the variables into a function i.e. var fev1 = document.getElementById('fevOne').value, but am not sure how to go about comparing each against one another apart from writing out every single possible case..
Does anyone have any idea how I should approach this?
My very sparse example code is below....
<head>
function reproduce() {
var fev1 = document.getElementById('fevOne').value;
var fev2 = document.getElementById('fevTwo').value;
var fev3 = document.getElementById('fevThree').value;
var fev4 = document.getElementById('fevFour').value;
var fev5 = document.getElementById('fevFive').value;
var fev6 = document.getElementById('fevSix').value;
//essentially, I don't know where to begin in building this formula, but imagine that I would need to use a loop
}
</head>
<body>
<input type="text" name="fevOne" id="fevOne" value="">
<input type="text" name="fevTwo" id="fevTwo" value="">
<input type="text" name="fevThree" id="fevThree" value="">
<input type="text" name="fevFour" id="fevFour" value="">
<input type="text" name="fevFive" id="fevFive" value="">
<input type="text" name="fevSix" id="fevSix" value="">
</body>
For a bit of background, I am building a medical form which will identify whether the lung function measurements (forced expiratory volume in 1 second, FEV1, measured in Litres) were collected with sufficient reproducibility (ie. 3 within 0.2L of one another), with the intent that the highest of these 3 values is taken as the clinically relevant value, stored for the patient.
Thanks in advance for any help!
Rory

Quick and dirty: https://jsfiddle.net/8081wucv/2/
function check() {
var text = document.getElementById('check');
Declare the function and get the element where I will put the bit of text
var values = [];
for (var i = 0; i < 6; i++) {
var value = document.getElementById('fev' + i).value;
if (/\d+\.?\d*/.test(value)) {
values.push(value);
}
}
Initialise the array and loop over the elements. If they're just digits with an optional point then push it onto the array
values.sort();
var passing = false;
Sort the array so we can do the next check easily and initialise the boolean that says whether or not the test passed.
for (var x = 0; x < values.length; x++) {
if (values[x + 2] - values[x] <= 0.2) {
passing = true;
break;
}
}
Loop over the array. If there are 3 elements (2 elements ahead, in the sorted array, minus this element) that have a difference of 0.2 or less then the test passes.
if (passing) {
text.innerHTML = 'passing';
} else {
text.innerHTML = 'not passing';
}
}
Update the text.
You can remove the final block and change it to return passing; if you just want a function.

The general idea would be check all inputs anytime a change is made to one of them using a nested loop structure that compares all combinations of inputs. It has to be bullet proof for clinical use and allow technicians to change their minds and erase, alter and correct values. Note that if the spirometry tests have been completed and all results are entered, this example reports the maximum clinical fev identified, not the one that minimizes the difference between two test results.
Note the HTML of this example identifies each input using a zero based "data-index" attribute, not "id" property. The "fevSetup" function would normally be called after the window load event has fired while running the snippet calls it directly. The maximum difference was increased slightly because JavaScript
decimal arithmetic is not always exact ( I haven't stored the text input by the technician which might be better for reporting purposes).
function fevSetup() {
var MAX_DIFF = 0.2000001;
var values = [];
var i,j;
var fevInputs = document.querySelectorAll('[data-type=fev]');
for( i = 0; i < fevInputs.length; ++i) {
fevInputs[i].addEventListener("change", checkFev);
}
function checkFev() {
var thisFev = Number( this.value);
var index = Number(this.dataset.index);
if(isNaN( thisFev) || thisFev <= 0) {
console.log("Invalid input: " + this.value)
this.value = "";
thisFev = undefined;
}
values[ index] = thisFev // may erase a previous entry
var clinicalFevs = [];
for( var i = 0; i < values.length-1; ++i) {
for( var j = i+1; j < values.length; ++j) {
if( values[i] && values [j]
&& (Math.abs( values[j] - values[i]) <= MAX_DIFF)) {
clinicalFevs.push( Math.max (values[i], values[j]));
}
}
}
if( clinicalFevs.length) {
var clinicalFev = Math.max.apply(Math, clinicalFevs);
console.log("Clinical Fev: %s", clinicalFev);
}
}
}
// window.addEventListent("load", fevSetup);
fevSetup(); // for testing
<input type="text" data-type="fev" data-index="0" value="">
<input type="text" data-type="fev" data-index="1" value="">
<input type="text" data-type="fev" data-index="2" value="">
<input type="text" data-type="fev" data-index="3" value="">
<input type="text" data-type="fev" data-index="4" value="">
<input type="text" data-type="fev" data-index="5" value="">
Naturally this code is supplied as is, without any form of guarantee or statement of fitness for purpose. I hope, however, it provides you with something to go on.

Not sure about this, but what about comparing Min and recurse ?
var inp = document.querySelectorAll('input'), // Jack's solution is more elegant.
fevArray = [];
[].forEach.call(inp, (e) => {
if (e.value) {
fevArray.push(parseFloat(e.value,10));
}
});
var recursiveCheck = function(arr){
if (arr.length >= 3) {
// If Max and min difference is not in the interval, change max with the second greatest value and recurse.
if ((Math.max.apply(null, arr) - Math.min.apply(null, arr) <= 0.2)) {
return arr;
}
recursiveCheck(arr.splice(arr.indexOf(Math.max.apply(null, arr)),1));
}
}
console.log("result", recursiveCheck(fevArray)); // should return undefined if not meeting conditions, or the array otherwise.

Related

How to create flexible input-fields in Javascript?

I am having problems to create the following situation:
I want to create inputfields, where I can write "1", "2" or "3" in any order, but each number is only allowed to be writen once.
Repeating one of those three numbers and writing other numbers than those three in the inputfields should be considered bad.
What do I need to add to the code?
a = 1
b = 2
c = 3
L = a
L = b
L = c
function F1() {
feedBack = document.getElementById("feedBack");
an = document.getElementById("userAnswer");
L = document.getElementById("L").textContent;
if (an == L) {
feedBack.textContent = "good";
} else {
feedBack.textContent = "bad";
}
}
<input id="userAnswer" type=text>
<input id="userAnswer" type=text>
<input id="userAnswer" type=text>
<button onclick="F1()">check</button>
<label id="L"> </label>
<p id="feedBack"> </p>
It's worth mentioning (especially for the more novice JavaScripters reading this) that, as with most programming problems, there are lots of ways to correctly satisfy the requirements from the original question.
I know this isn't Code Review.SE, but you might benefit from some feedback on the example you provided, if you're interested:
The variables a, b, and c are never used in any particularly useful way, and detract from the human readability of your code. You should probably remove their declarations entirely.
You set the variable L three times consecutively. This doesn't do very much at all, considering also L is overridden once F1() is executed. You should probably remove these unnecessary assignments entirely.
The HTML specification is clear that ID values should be unique across the entire document space; anything else is invalid and can lead to headaches and undocumented behavior down the line, especially when JavaScript comes into play. In the simplified example, there really isn't any need to assign them IDs at all (see solution).
Relatively minor, but inline event handling (i.e., using the onclick attribute) is generally regarded as an outdated concept. Instead, use the addEventListener() paradigm to make your code easier to interpret and debug.
The function name F1() isn't particularly descriptive to what the function actually does when called. A future developer maintaining your code would have a less difficult time discerning what this method does if it was named something more descriptive, like validateForm(), or even just validate().
To satisfy your requirements, you might look to write something more like what I've got below. In a nutshell, when the validate() function is run, the following actions are taken:
Instantiates validNumbers, an array of the valid inputs to be validated against he fields.
Instantiates inputFields which evaluates to a NodeList iterable which can be looped.
Instantiates feedbackElement, a reference to your <p> node in the DOM.
Loops all the inputFields, and checks if the value of the current field is in the validNumbers array.
If the validation is successful, the code removes the valid value from the validNumbers array (as it's already been used and can't be used again) and proceed to validate the next field.
If the validation is unsuccessful, the code automatically sets the text of your feedback element to "bad" and breaks out of the validation loop.
Once all three input fields have been validated, the code checks to see if there are any remaining elements of validNumbers left. If there are, not all elements were used and the feedback is once again set to "bad". Otherwise, the validation checks out and the feedback element's contents are set to "good".
function validate() {
var validNumbers = [1, 2, 3];
var inputFields = document.querySelectorAll("input[type='text']");
var feedbackElement = document.querySelector("p#feedBack");
for (field of inputFields) {
var fieldValue = parseInt(field.value);
if (validNumbers.includes(fieldValue)) {
// valid number & not encountered yet
validNumbers.splice(validNumbers.indexOf(fieldValue), 1);
} else {
// invalid number or already used
feedbackElement.innerText = "bad";
break; // break out of `for` loop, as there's already no possible way for the provided numbers to be "good"
}
}
if (validNumbers.length === 0) {
// all numbers were used
feedbackElement.innerText = "good";
} else {
// not all numbers were used
feedbackElement.innerText = "bad";
}
}
document.querySelector("button").addEventListener('click', function() {
validate();
});
<input type=text>
<input type=text>
<input type=text>
<button>check</button>
<p id="feedBack"> </p>
You could try to loop over the input elements and then validate each element, in the loop save the value of the input in a set/array for each input so with this we would have a cache to check the input field values.
function validate() {
let numberEntered = new Set();
let allowedValues = [1, 2, 3];
let inputStatus = false;
let feedBack = document.getElementById("feedBack");
let inputEle = document.querySelectorAll(".number-field");
for (let input of inputEle) {
let value = parseInt(input.value);
if (allowedValues.includes(value) && !numberEntered.has(value)) {
numberEntered.add(value)
} else {
inputStatus = true;
break;
}
}
if (inputStatus) {
feedBack.textContent = "Bad";
} else {
feedBack.textContent = "good";
}
}
<input id="userAnswer1" class="number-field" type=text>
<input id="userAnswer2" class="number-field" type=text>
<input id="userAnswer3" class="number-field" type=text>
<button onclick="validate()">check</button>
<label id="L"> </label>
<p id="feedBack"> </p>

Using an array of numbers to add up to a specific number

I've been trying to find out an efficient method of finding multiple numbers from an array that add up to a given number. In this instance I'm trying to find 3 numbers that total a target number.
I've got a basic working example below but unfortunately the recursive loop fails, it looks like there's an issue with it constantly looping. Ideally it would find the first possible answer and return it, but when it can't find an answer it gets stuck in the loop and breaks the browser.
Warning: the below code will break due to a memory leak:
let array = [5,6,3,3,6,67,2,2,6,7,7,2,1,3,4,5,67,7,4,2,5,6,3,3,6,67,2,2,6,7,7,2,1,3,4,5,67,7,4,2,5,6,3,3,6,67,2,2,6,7,7,2,1,3,4,5,67,7,4,2];
function findSums(arr, target, count) {
var result = [];
function recurse(start, leftOver, selection) {
if (leftOver < 0) return; // failure
if (leftOver === 0 && selection.length == count) {
result.push(selection); // add solution
return;
}
for (var i = start; i < arr.length; i++) {
recurse(i, leftOver-arr[i], selection.concat(arr[i]));
}
}
recurse(0, target, []);
return result;
}
// Demo
$('#input').on('blur', function(e){
let value = parseInt(e.target.value);
let result = findSums(array, value, 3);
if(result.length > 0){
$('#output').text(result[0]);
} else {
$('#output').text('Nothing found');
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Input Number Below</h1>
<input id="input" type="number" />
<code id="output" ></code>
Well, it didn't break, when I tested, but still here are some tips:
You should set additional limitation to the count. You are making to much extra calls. When your function deals with really big sum, small numbers and small count it will call itself again until it reaches or overflows the desired sum, and only after that it will check current count. So you should add
if (selection.length > count) return;
Also. As I see there are many duplicates in your array, so I assume, that usage of the same number is allowed, but only if it is taken from another index. In your loop you are calling next recurse with the same start index. I think, you need
for (var i = start; i < arr.length; i++) {
recurse(i + 1, leftOver-arr[i], selection.concat(arr[i]));
}
And finally. This will not influence the recursive part of an algorithm, but maybe you'd like to filter out same results, or filter out your array to remove all duplicates.
Hope this helps.
Edit: sorry, missed the part about first possible solution. Here is the way to achieve this:
function recurse(start, leftOver, selection) {
if (leftOver < 0) return false; // failure
if (selection.length > count) return false;
if (leftOver === 0 && selection.length == count) {
result.push(selection); // add solution
return true;
}
for (var i = start; i < arr.length; i++) {
var res = recurse(i + 1, leftOver-arr[i], selection.concat(arr[i]));
if (res) return true;
}
}

How do I reference text boxes using a variable

So I am making a small quiz on JavaScript for the first time. I wanted the user to be able to select between 3 options(a, b and c) by entering the letter in a text box and clicking a button to check the answer. A text will then appear underneath the text box to show whether the user entered the right option or not.
I have managed to make this work but since there are multiple questions, I wanted to use a for loop to loop through each text box (I named each text box "0", "1" ...) but I cannot reference them using i. How can I do it?
Here is my JavaScript:
var answer = ["a", "b", "c"];
var results = "results"
function check() {
for (i = 1; i = 4; i++) {
var input = document.getElementById(i).value;
if (input == answer[parseInt(i-1)]) {
document.getElementById(results.concat(i)).innerHTML = "Correct";
}
else {
document.getElementById(results.concat(i)).innerHTML = "Wrong";
}
}
}
Here is the HTML (I repeated the same code for each question with a different ID):
<input type="text" id="0" value="a, b or c"><br>
<input type=button value="Check" onClick="check()"><br>
Result: <span id="results0"></span><br><br>
This should work:
There are a few things wrong with your original code
Wrong:
for (i = 1; i = 4; i++)
usually we start our iterations on 0 index, also the middle portion of the for loop should return truthy which means it should evaluate to true or false "i = 4" will never be either because = is an assignment operator, you should use evaluation operators >, <, >=, ==, etc.
for (i = 0; i < 3; i++) {
var input = document.getElementById(i).value;
if (input == answer[i]) {
document.getElementById("results" + i).innerHTML = "Correct";
}
else {
document.getElementById("results" + i).innerHTML = "Wrong";
}
}
Additionally you were using "result" like a variable in this:
results.concat(i)
So results would need to be a variable that contains the string "results" which I doubt is the case. so what we are telling the getElementById method by doing it this way
document.getElementById("results" + i)
is to find an element with an ID of "results" plus the index of the loop eg. id="result0", or id="result1" etc.
If you have all of these within a <div> or div tag you can reference them using :nth-child notation. This works by referencing the nth child from the beginning.
$("div:nth-child(i)");
With the html you provided your for loop is incorrect.
Since you started your input at 0 you want to start looping at 0.
for (i = 0; i <= 2; i++) { //with three values 0,1,2
...
}
Your <span> tag also need to be closed with a </span>
Looping through id's feels very dirty to me. From a maintenance and readability standpoint, I recommend you loop through a collection of Nodes instead.
I believe that you are looking for:
document.getElementsByClassName("someClass")[0];
Where [0] Would be the index of the element whos class is shared.
Here is a code sample I wrote for you to reference using textboxes and outputting the values into a div within a for loop.
https://jsfiddle.net/4ocnyy38/1/
You can dynamically create inputbox and result span and alot dynamic ids to them and then check the correct answer on click of button
Javascript:
var answer = ["a", "b", "c"];
var results = "results";
setTimeout(function(){
var injectData='';
for(var i=0;i<3;i++){
injectData+="<input type='text' id='id_"+i+"' placeholder='a, b or c'/> Result: <span id='results_"+i+"'></span><br/>";
}
document.getElementById('inject').innerHTML=injectData;
},500);
function check() {
for (i = 0; i <3; i++) {
var input = document.getElementById('id_'+i).value;
if (input == answer[i]) {
document.getElementById("results_"+i).innerHTML = "Correct";
}
else {
document.getElementById("results_"+i).innerHTML = "Wrong";
}
}
}
HTML:
<div id="inject">
</div>
<input type=button value="Check" onClick="check();"><br>
Demo: https://jsfiddle.net/9ea46of5/

value method not working function callback

I am creating a small program that returns the results of a mathematical equation. I have a number input field with the ID and CLASS "value1" (I've attempted to manipulate using both) that allows the user to put in a number value. I have another number input field that is disabled with the ID and CLASS "result1" that displays the results of the equation.
I have a button with the ID solution1_btn that when clicked is suppose to initiate the "multiples" function callback which takes "value1" as an argument.
When I replace "value1" which a physical number e.g. 1000, the results of the equation appears in "result1" without pressing solution1_btn, however when i put "value1" as the argument and press solution1__btn it does not work.
Below is the section of JavaScript code that I have narrowed the problem to and HTML.
JS:
// declare Euler1 assign it to function with parameter num
// click button
var solution1 = document.getElementById("solution1_btn");
// user entered value
//var value1 = document.getElementById("value1");
var value1 = document.getElementsByClassName("result1")[0].value;
//console.log(value1);
// result input field
var result1 = document.getElementById("result1");
function multiples(num) {
// declare sum assign it value 0
var sum = 0;
// declare a for loop that iterates while the counter "i" is less than num
for (var i = 0; i < num; i++) {
// if statement test whether the division remainder of 3 and 5 are equal to 0
if (i % 3 || i % 5 === 0) {
// assigns the value of i to sum
sum += i;
var newSum;
result1.value = newSum;
newSum = sum;
};
};
// returns the value of sum from the function callback argument 1000 etc.
return newSum;
};
var fix = value1;
solution1.onclick = multiples(fix);
HTML:
<label for="value">Enter Value: </label>
<input id="value1" class="value1" type="number" title="value field" placeholder="e.g. 1000">
<button type="button" id="solution1_btn" title="solution 1 button">Enter</button>
<input id="result1" class="result1" type="number" disabled>
Gosh, there is quite a few problems with your code, I'll try to run through them all.
Referencing HTML elements
HTML elements can be referenced in many ways, as you have discovered. Generally, you should pick the most appropriate and stick with it. If you use an id and a class things get confusing quickly - espcially seeing as id's should be unique, but classes need not necessarily be so. In your case, I think you're safest to stick with id, and then always use document.getElementById.
Multiple boolean checks
Regarding this line of code
if (i % 3 || i % 5 === 0) {
You probably expect that that equates to "if i is divisible by 3 or 5", and that is a logical (and often misunderstood) part of boolean logic. In actual fact, you should think "if i is divisible by 3 or i is divisible by 5", which equates to the following in code
if ((i % 3) === 0 || (i % 5) === 0) {
Yes, unfortunately you need to repeat the === 0 part twice.
Variable scope
This one's a big subject, and there is plenty of other information on the subject, but suffice it to say that in your function newSum is defined only inside an if block, and is redefined every iteration of your loop, so it wont contain the sum as you may be expecting.
In any case, it's uneccessary, you should just return sum
function multiples(num) {
// declare sum assign it value 0
var sum = 0;
// declare a for loop that iterates while the counter "i" is less than num
for (var i = 0; i < num; i++) {
// if statement test whether the division remainder of 3 and 5 are equal to 0
if ((i % 3) === 0 || (i % 5) === 0) {
// assigns the value of i to sum
sum += i;
};
};
// returns the value of sum from the function callback argument 1000 etc.
return sum;
};
Event handlers
You are trying to set an event to occur onclick with this code
solution1.onclick = multiples(fix);
This attempts to add an event handler with the result of calling multiples - not multiples itself. You should assign the event handler a function, and assign the value of the field to the result of calling the multiples function.
solution1.onclick = function(){
result1.value = multiples(parseInt(value1.value,10));
};
Working example
Below is a working example of your code, hopefully helps you pull this all together.
var solution1 = document.getElementById("solution1_btn");
var value1 = document.getElementById("value1");
var result1 = document.getElementById("result1");
function multiples(num) {
// declare sum assign it value 0
var sum = 0;
// declare a for loop that iterates while the counter "i" is less than num
for (var i = 0; i < num; i++) {
// if statement test whether the division remainder of 3 and 5 are equal to 0
if ((i % 3) === 0 || (i % 5) === 0) {
// assigns the value of i to sum
sum += i;
};
};
// returns the value of sum from the function callback argument 1000 etc.
return sum;
};
solution1.onclick = function(){
result1.value = multiples(parseInt(value1.value,10));
}
<label for="value">Enter Value: </label>
<input id="value1" class="value1" type="number" title="value field" placeholder="e.g. 1000">
<button type="button" id="solution1_btn" title="solution 1 button">Enter</button>
<input id="result1" class="result1" type="number" disabled>
Here is a fiddle with you problem - I hope solved: http://jsfiddle.net/w0qvdqb2/
There are few different problems in your code, first:
solution1.onclick = multiples(fix);
this means that multiples method should execute and return value is assigned to variable solution1.onclick but solution1.onclick accept callback.
Than based on your comments condition hasn't beed written as it's described.
And mixing with inputs and outputs classes and ids.
Please review updated code.

Trying to make a Javascript Array Print out using Inputted value

my first question would be am I correctly getting the value from id "textOne" into my var a? Second, I am supposed to have my while loop run "while the variable that represents the index value that I want to print" is greater than or equal to the minimum array value. Is my While loop condition correct?
I just basically want this to print out the correct number of indexes within my array based on the user input ranging from 1-5.
Thanks in advance.
<input type="button" value="Click" onclick="JobDuties()" />
to see my top
<input type="text" id="textOne" />
job duties here
<p id="answer"></p>
<script type="text/javascript">
function JobDuties()
{
var x = "";
var a = document.getElementById('textOne').value;
var b = a - 1;
myduties = new Array();
myduties[0] = "Saab";
myduties[1] = "Volvo";
myduties[2] = "BMW";
myduties[3] = "Toyota";
myduties[4] = "Ford";
}
while (a>=0)
{
x = x + myduties[b];
document.getElementById("answer").innerHTML=x;
}
</script>
I will assume you want to print out the correct array value, not arrays, as there are not multiple. PS> People do not like homework questions on here if you do not say so because answering completely does not help you learn. I will partially answer.
You do not need to loop through the array to look up a value.
You can initialize the array more easily.
["Saab", "Volvo", ... ]
You can reference a position in the array, like so for Saab as it is zero indexed
myduties[0]
If you are going to loop, which I am still not seeing why you would do that.
Code below:
var i = 1; //The variable you increment up to the use input variable a
while(i =< myduties.length){
if(i == a){ //if i and a are same then that position
//in the array will have the car type the user requested
myduties[i-1] //and set it to the DOM or document element similar to what you already had
}
i = i + 1; //Increment i towards the one less than the length of the array
}
Not perfect or checked but that should provide you with some pointers.

Categories