How to display the updated element in javascript array - javascript

I have a javascript issue. Suppose I have an input box that the user can enter the values and I store them in an array and display the array. Values like:
apple 8, orange 4, pear 10, orange 3.
What I want to do is to show the latest updated added value so when the user wants to see the values they see which is (all values in the array plus the latest updated value) so I dont want to show orange 4! I want to show orange 3 instead.
apple 8, pear 10, orange 3. //numbers are quantity of fruits that I randomly set
So the orange with the quantity of 4 is replaced y the orange with quantity of 3. This is my code for creating array, I think I should use key value store or hash instead, to display the last updated value, can you give me any hint? Thanks
this.fruitArray.push(inputData);
this.fruitArray = this.removeDuplicate(this.fruitArray);
if(inputData !== "" ){
$('#displayBox').html(this.fruitArray);
}
removeDuplicate: function(Arr){
var cur, found;
for (i = Arr.length - 1; i >= 0; i--) {
cur = Arr[i];
found = false;
for (j = i - 1; !found && j >= 0; j--) {
if (cur === Arr[j]) {
if (i !== j) {
Arr.splice(i, 1);
}
found = true;
}
}
}
return Arr;
},

if you just want access to the last element of an array, you can do it like this:
var lastElement = myArray[myArray.length-1]
in your case:
$('#displayBox').html(fruitArray[fruitArray.length -1]);
example: FIDDLE
--EDIT---------------------------
Still not sure of what you try to achieve, but could you just store the last fruit update in an other variable ?
var fruitArray = [];
var lastFruitUpdate = "";
....
if(inputData !== "" ){
lastFruitUpdate = inputData;
if(fruitArray[inputData] != undefined){
fruitArray[inputData]++;
}else{
fruitArray[inputData] = 1;
}
$('#displayBox').html(lastFruitUpdate+"( "+fruitArray[lastFruitUpdate]+")");
}
example: FIDDLE

If you want last element of array which is just added into array, then use below statement.
this.fruitArray.push[this.fruitArray.length-1]

Related

simple elevator in javascript

I'm trying to code a solution to the following challenge question found on codewars.com:
There is a house with 4 levels. In that house there is an elevator. You can program this elevator to go up or down, depending on what button the user touches inside the elevator.
valid levels can be only these numbers: 0,1,2,3
valid buttons can be only these strings: '0','1','2','3'
possible return values are these numbers: -3,-2,-1,0,1,2,3
If the elevator is on the ground floor(0th level) and the user touches button '2' the elevator must go 2 levels up, so our function must return 2.
If the elevator is on the 3rd level and the user touches button '0' the elevator must go 3 levels down, so our function must return -3.
If the elevator is on the 2nd level, and the user touches button '2' the elevator must remain on the same level, so we return 0.
We cannot endanger the lives of our passengers, so if we get erronous inputs, our elevator must remain on the same level. So for example:
goto(2,'4') must return 0, because there is no button '4' in the elevator.
goto(4,'0') must return 0, because there is no level 4.
goto(3,undefined) must return 0.
goto(undefined,'2') must return 0.
goto([],'2') must return 0 because the type of the input level is array instead of a number.
goto(3,{}) must return 0 because the type of the input button is object instead of a string.
I can came up with the following code but I am failing about 40% of the test case. Can someone tell me where I am wrong with my logic:
function goto(level,button){
var arr = [0, 1, 2, 3];
var result = 0
for(var i = 0; i < arr.length; i++){
for(var j = 0; j < arr.length; j++){
if(level === arr[i] && button === arr[j]){
if(level < button){
result = level + button;
}else{
result = button - level;
}
}
}
}
return result;
}
I am refactored my code, but I am still failing 1 of 31 test cases with the following message given:
Expected: 0, instead got: 1
Refactored code:
function goto(level,button){
var valid = [0, 1, 2, 3];
button = Number(button);
if (typeof level === 'number' && typeof button === 'number') {
for(var i = 0; i < valid.length; i++){
for(var j = 0; j < valid.length; j++){
if(level === valid[i] && button === valid[j]){
return button - level;
}
}
}
}
return 0;
}
I suspect it is because level is a number, however button is a string. In javascript, because of type conversions :
3 - '2'; // return 1
3 + '2'; // return '32';
Use the function Number() to convert your buttons string to a number, and you will have the true add behavior that you want.
You should do data format check first and also make it too complicated in calculating the result.
It should work as below.
function goto(level,button){
var floors = [0, 1, 2, 3];
var level_num = parseInt(level);
var button_num = parseInt(button);
if (typeof floors[level_num] == 'undefined' || typeof floors[button_num] == 'undefined') {
return 0;
}
return button_num - level_num;
}

Filtering array by index and matching values

I'm tying to filter out a pattern for a slot machine, in this case I want the following indexes to be selected if they have the same value.
If indexes 0, 2 and 6 has the same value if should be outputted.
I was thinking something like a function call maybe like this
if (win_filter([0, 2, 6] == "slot-2") {
console.log("You won");
}
My code is the following below.
var final_score = new Array();
$(".shoot").click(function() {
//var numbers_array = ["slot-1", "slot-1", "slot-1", "slot-1", "slot-1", "slot-2", "slot-2", "slot-2", "slot-2", "slot-3", "slot-3", "slot-3", "slot-4", "slot-4", "slot-5"];
var numbers_array = ["slot-1", "slot-2", "slot-3", "slot-4", "slot-5"];
var target = $("div.window table");
target.find("tr td > div").each(function() {
$(this).fadeOut(function() {
$(this).removeAttr('class');
$(this).addClass(numbers_array[Math.floor(Math.random() * numbers_array.length)]);
$(this).fadeIn();
final_score.push($(this).attr("class"));
});
});
function filterResults(arr) {
return final_score.filter(function(el) {
return arr.some(function(e) {
return el.timeframe == e;
});
});
}
var result = filterResults(['0','2','6']);
console.log(result);
$.each(numbers_array, function(index, value) {
if (result == value) {
$(".notice").html("You have won.").addClass("success").show();
console.log("You won!");
}
});
console.log(final_score);
});
Edit
If it wasn't clear I meant the indexes in the array, in case if I picked the indexes 0, 2 and 6 from this generated array the value of those would be (even if they aren't the same).
0 => "slot-2", 2 => "slot-5", 6 => "slot-1"
The goal is to check if the selected indexes has the same value output.
And the amount of indexes shouldn't be hardcoded, it can be anything from 3 index searches to 5 index searches.
jsFiddle.net
Array[0]
0 : "slot-2"
1 : "slot-3"
2 : "slot-5"
3 : "slot-5"
4 : "slot-4"
5 : "slot-3"
6 : "slot-1"
7 : "slot-4"
8 : "slot-1"
9 : "slot-2"
10 : "slot-2"
11 : "slot-4"
12 : "slot-5"
13 : "slot-1"
14 : "slot-4"
First of all, I avoided to make any major modifications to your code, so in the jsfiddle I wrote the validation exactly where you were expecting it (inside the on('click')).
What I did:
Previous to calculating anything, we need the slots data. You were already saving it inside final_score, but the function which was doing so was a callback. Is it worth it waiting for the callback? - I do not think so, because it is a simple css (fadeOut) animation.
const classVal = numbers_array[Math.floor(Math.random() * numbers_array.length)];
$(this.fadeOut(function() { // Rest of your code }
final_score.push(classVal);
Calculate the length of each row, you know that they will all be equal length and you have all of them inside an array (final_score), so a simple division by the number of lines is enough.
const lines = 3;
const lineLength = final_score.length/lines;
For each line we check whether the other line values are the same as this one. Given that your array order is not based on the display order but rather on the order you generated them, we can simply check the ones with the same index (but iterating over each line).
final_score[i] === final_score[i+lineLength] && final_score[i] === final_score[i+lineLength*2]
Resulting in:
const lineLength = final_score.length/3;
for(let i=0; i<lineLength; i++) {
if (final_score[i] === final_score[i+lineLength] && final_score[i] === final_score[i+lineLength*2]) {
console.info(`win col ${i}`);
}
}
If you need it, you can easily n-ify this.
const lineLength = final_score.length/3;
for(let i=0; i<lineLength; i++) {
const lineOneSlot = final_score[i];
let allEqual = true;
for (let j=1; j<lines; j++) {
console.info(`Comparing ${i} ${i+lineLength*j}`);
if (lineOneSlot !== final_score[i+lineLength*j]) {
allEqual = false;
break;
}
}
if (allEqual) {
console.info(`win col ${i}`);
}
}
Since you asked for a diagonal check as well, it would look like this:
However, you have to make sure that the grid is a square to get your expected results. Otherwise, you would have to redefine what exactly to do in these cases.
final_score[i] === final_score[i+1+lineLength] && final_score[i] === final_score[i+line+lineLength*line]
https://jsfiddle.net/qjp7g0qL/3/
Reading through your breifing and comments, get the idea that you are trying to create some slot machine, where the center row is used for the matching evaluation. Hence changed a few lines in your code to get it done. JS FIDDLE DEMO
NOTE: I have tried two approach, for a WINNER state.
1. All items of CENTER ROW should be the same.
2. All items of CENTER ROW should be laid out in the same as the PATTERN
FYI: COMMENTED LINE 21 in JS for easy testing ...
/* checks if selected items are matching the winning pattern ... */
function areItemsMatchingWinningPattern(selectedItems, winningItemsPattern) {
return !!selectedItems && !!winningItemsPattern && (selectedItems.length == winningItemsPattern.length) && selectedItems.every(function (elm, idx) {
return elm === winningItemsPattern[idx];
})
}
/* checks if all selected items are same .... */
function areAllItemsMatching(source) {
return !!source && source.length > 0 && source.every(function (elm, idx, array) {
return idx === 0 || array[idx - 1] == elm;
});
}
This scheme could check for winning conditions given a non-empty arbitrary length list of valid indexes. Here is the working JSFiddle.
var win_filter = function(indexes, allValues) {
// assumes all indexes are valid
// gather all the values from the slot machine by index.
var values = [];
for (var i = 0; i < indexes.length; i++)
values.push(allValues[indexes[i]]);
// if every value matches the others, then all values match the first
if (values.every(function(x) { return x == values[0]; }))
return values[0]; // return the value that was the same
// No match found, return null to signify that no winning condition was found.
return null;
}
$(".shoot").on('click', function() {
var final_score = [];
var numbers_array = ["slot-1", "slot-2", "slot-3", "slot-4", "slot-5"];
// ...
// Instead of iterating through the possible winning values, if there was any match, it means they won, and winningMatch will contain that matching value. ie 'slot-1'
var winningMatch = win_filter([0, 2, 6], final_score);
if (winningMatch) {
$(".notice").html("You have won.").addClass("success").show();
}
});
Note that if any matching set of any available class name wins, then we don't have to iterate through the list of possible winning cases to determine that the game was won, because wouldn't any match win?
You asked for a comparison function, here it is:
function compareMultiple(sourceArray, indexesArray, compareToValue){
for (let i = 0; i < indexesArray.length; i++){
let index = indexesArray[i]
if (!sourceArray[index] || sourceArray[index] !== compareToValue) {
return false
}
}
return true
}
It accept three arguments: array of values, array of indexes to pick items and value to match the condition. Function returns a true / false. You can call it this way:
let isWin = compareMultiple(
['slot-1','slot-2','slot-1','slot-3','slot-4', 'slot-2', 'slot-1'],
[0, 2, 6],
'slot-1'
)
console.log(isWin); // true
Here is an example (i reduced number_array to increase a chance to win and rewrite a little bit of code just for demonstration). In this example i also used promises to wait until jquery fadeOut animation will be completed and we can check if new combination of slots is win (since you put new values in a final_score only on fadeOut complete asynchronous callback but check it right after the $.each your fiddle wont work as expected).
Fiddle: https://jsfiddle.net/q3eh0n9f/4/
var options = [
"slot-2",
"slot-3",
"slot-5",
"slot-5",
"slot-4",
"slot-3",
"slot-1",
"slot-4",
"slot-1",
"slot-2",
"slot-2",
"slot-4",
"slot-5",
"slot-1",
"slot-4"
];
// convert selections to usable values and filter unique elements
function buildResults (arr) {
return arr.map(function (index) {
return options[index];
}).filter(function (value, i, arr) {
return arr.indexOf(value) === i;
});
}
// if array has been reduced to the length of 1 it is a winner
function checkResults (results) {
if (results.length === 1) return true;
if (results.length !== 1) return false;
}
var result = checkResults(buildResults([0, 2, 3]));
console.log(result); // false

find top k elements in array

I have an array in the format:
var series = [[horse,1],[cat,2],[dog,4],[dragon,4],[cow,6]]
In order to find the top 3 elements based on the 2nd parameter I sort the array. So for this purpose I use the code below:
series.sort( function(a,b) {
if (a[1] === b[1]) {
return 0;
}
else {
return (a[1] < b[1]) ? 1 : -1;
}
});
Which works fine. Then If I want to find the top 3 I can always select [0,2]. However, if the 4th value equals the the 3th then I miss it. In this case if I ask for the top 3 the output should be [[horse,1],[cat,2],[dog,4],[dragon,4] because dragon and dog have equal value (4). So, I wonder is there some library I could use out of the box or some efficient algorithm to return the top 3 values which does not necessarily mean returning top 3 element arrays?
Just build a list:
var top = [];
top.push(series[0]);
top.push(series[1]);
for (var i = 2; i < series.length && series[i][1] == series[2][1]; ++i)
top.push(series[i]);
To generalize that (a little):
function top(series, k) {
var top = [];
for (var i = ; i < k - 1; ++i)
top.push(series[i]);
for (; i < series.length && series[k-1][1] == series[i][1]; ++i)
top.push(series[i]);
return top;
}
var series = [["horse",1],["cat",2],["dog",4],["dragon",4],["cow",6]]
num = 3;
var arr = [];
for(var i=0; i<series.length; i++)
{
var curr = series[i][1];
var next = series[i][1];
if(i<num)
{
arr.push(series[i]);
}
else if(curr==next)
{
arr.push(series[i]);
break;
}
}
console.log(arr);
So I would make a second array (length of 3) and loop through the initial array. When The first three items should be automatically added to the array. Then as we loop through the first array and find values higher than the lowest value we remove the lowest value and place the new item in the new array in its proper place.
var series = [[horse,1],[cat,2],[dog,4],[dragon,4],[cow,6]];
function top3(a){
// Create a new Array to hold the top values
var top = [a[0], a[1], a[2]]; // Initialize it with the first three items
for(var i=3;i<a.length;i++){
/* Find the minimum value and its position */
var min = top[0][1];
var min_pos = 0;
for(var e=1;e<3;e++){
if(top[e][1]<min){
min = top[e][1];
min_post = e;
}
}
/* If larger than the top arrays minimum */
if( a[i][1] > min ){
/* remove the top arrays min */
top.splice(min_pos, 1);
}
/* Add the new item into the top array */
top.push(a[i]);
}
/* Now our "top" array has the items with the top 3 values, if you want them sorted use a bubble sort here, if not just return "top" */
bubbleSortByIndex(a, 1); // Sorts by the second item in an array or arrays
return top;
};
/*
Bubble Sort Algorythm adapted from http://en.wikipedia.org/wiki/Bubble_sort
*/
function bubbleSortByIndex(a, i){
var swapped;
do {
swapped = false;
for(var e=1;e<a.length-1;e++){
if( a[e-1][i] > A[e][i]){
swapped = true;
var temp = a[e-1];
a[e-1] = a[e];
a[e] = temp
}
}
} while (swapped);
return a;
}
top3(series);
This leaves the original array in tact and finds the top three items only, and sorts those. If you wanted the entire original array sorted then just call bubbleSortByIndex(series, 1) and ignore the whole "top3()" function.

Range filtering and splicing an array of arrays

I have an array of arrays that I'm filtering with a range slider. If the value of the specific selected parameter is within the user's set minimum (tMin) and max (tMax) values, it adds that to the new array (myNewArray) and reformats it in a way I need. Anything that is out of the range doesn't get added to this new array. This part works perfectly fine.
The thing I can't seem to get working is I have a separate array (myOtherArray) which is formatted exactly the same as myArray, but instead of reformatting it I just need to remove the row if it doesn't fall within the range. myOtherArray should have the same values and number of rows as myNewArray, but they are both just formatted differently. What am I doing wrong here?
myArray.map(function (dataPoint, index) {
if (index > 0) {
dataPoint.map(function (value, column) {
// this first part works fine
if ( dataPoint[paramToFilter] >= tMin && dataPoint[paramToFilter] <= tMax ) {
myNewArray[column] ? myNewArray[column].push(+value) : myNewArray[column] = [+value]
}
// this is what I cannot get to work
if ( dataPoint[paramToFilter] < tMin || dataPoint[paramToFilter] > tMax ) {
myOtherArray.splice(index, 1);
}
})
}
})
thank you!!
The problem is that the values of myOtherArray are not on the same index as in myArray once you called myOtherArray.splice(index, 1).
Here is a small example showing the problem: http://jsbin.com/wipozu/1/edit?js,console
In order to avoid this problem you could simply "mark" those array items to be removed instead of removing it immediately. When you finished all checks (after myArray.map(...)) you could then remove all those "marked" items.
So instead of calling myOtherArray.splice(index, 1); you replace the item with undefined (or any other value) --> myOtherArray[index] = undefined;
And afterwards run the following for in order to remove all those undefined items.
for (var i = 0; i < myOtherArray.length; i++)
{
if (myOtherArray[i] === undefined)
{
myOtherArray.splice(i, 1);
// correct the index to start again on the same position because all
// followings item has moved one index to the left in the array
i--;
}
}
The same example from before but using my solution: http://jsbin.com/wipozu/2/edit?js,console
So your code looks like this then:
myArray.map(function (dataPoint, index) {
if (index > 0) {
dataPoint.map(function (value, column) {
if ( dataPoint[paramToFilter] >= tMin && dataPoint[paramToFilter] <= tMax ) {
myNewArray[column] ? myNewArray[column].push(+value) : myNewArray[column] = [+value]
}
if ( dataPoint[paramToFilter] < tMin || dataPoint[paramToFilter] > tMax ) {
myOtherArray[index] = undefined; // should be removed afterwards
}
})
}
})
// remove all items that have been marked
for (var i = 0; i < myOtherArray.length; i++)
{
if (myOtherArray[i] === undefined)
{
myOtherArray.splice(i, 1);
// correct the index to start again on the same position because all
// followings item has moved one index to the left in the array
i--;
}
}
The problem is that when you splice out an element, the indexes of all the following elements shift down. As a result, the indexes in myArray and myOtherArray are no longer in sync, and when you later do myOtherArray.splice(index, 1) you remove the wrong element.
The simplest solution is to iterate from high to low instead of from low to high:
for (var index = myArray.length-1; index > 0; index--) {
...
}

How to sum up distinct value using javascript

I want to try and sum up distinct value from a list.. currently i am able to do so if theres only 2 similar record. If theres more than 2 i am not able to do the checking. Following is the javascript code:
function validateData(){
var total = document.frm.size.value;
var msg="";
var tbxA;
var tbxB;
var tbxA2;
var tbxB2;
var tbxC;
var totalValue =0;
var repeatedValue= 0;
var row = 0;
var row2 = 0;
for(var i=0; i<parseInt(total); i++){
tbxA = document.getElementById('tbx_A'+i).value;
tbxB = document.getElementById('tbx_B'+i).value-0;
tbxC = document.getElementById('tbx_C'+i).value;
for(var j=i+1; j<parseInt(total); j++){
tbxA2 = document.getElementById('tbx_A'+j).value;
tbxB2 = document.getElementById('tbx_B'+j).value-0;
if (tbxA==tbxA2) {
totalValue = tbxB + tbxB2;
}
if (totalValue != tbxC) {
repeatedValue= 1;
row = i;
row2 = j;
msg+="*total value does not add up at row " +(row2+1);
break;
}
}
if(repeatedValue== 1){
break;
}
}
return msg;
}
For example A:type of fruit, B: total of each fruit, C: how many bought at a time
total of C should be equal to B. i.e Apple: 3+3+4 = 10. So if the total is not equals to 10 it should prompt me an error.
A B C
Apple 10 3
Orange 10 10
Apple - 3
Apple - 4
My code above will prompt error bt it doesnt go beyond 2nd occurence of Apple.
So yes, how should i go about to ensure it loop through the whole list to sum up all similar values?
Thanks in advance for any possible help!
Try this:
var total = +document.frm.size.value,
data = {};
for(var i=0; i<total; ++i) {
var key = document.getElementById('tbx_A'+i).value;
data[key] = data[key] || {B:0, C:0};
data[key].B += +document.getElementById('tbx_B'+i).value || 0;
data[key].C += +document.getElementById('tbx_C'+i).value || 0;
}
for(var i in data) {
if(data.hasOwnProperty(i) && data[i].B != data[i].C) {
return "total value does not add up";
}
}
return "";
Some comments:
parseInt (and parseFloat) is very slow. + operator before string converts it to a number much faster. But if you really want to make sure the numbers are integers, use Math.floor(), Math.round(), Math.ceil() or the faster but illegible |0.
In case you really want parseInt (e.g. you want to convert '123foobar' into 123), always use a radix. For example: parseInt('123', 10)
Avoid doing calculations at the condition of a loop, because they run at each iteration. Just do the calculation once before the loop and save the result in a variable.

Categories