Related
I have such a problem:
I have an array of data, and I have an array of time.
These are the arrays:
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
After a second I want to display the number 60, after 2.5 seconds the number 85, and so these ...
This is the code I've been trying to do so far, but it's not working for me
import React from "react";
function App() {
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
const scoreValue = (time, score) => {
time.forEach((timePoint, i) => {
setInterval(() => {
<p>{score[i]}</p>
}, timePoint * 1000);
});
}
return (
<div className="App">
{scoreValue(Reps.TimeOfMove, Reps.ScoreOfMove)}
</div>
);
}
export default App;
I want to display different text each time, according to the time it appears.
Try to create a state (currentScore) and set the value to it on interval, This is done by the forEach loop and setInterval.
import React, { useState } from "react";
function App() {
const [currentScore, setCurrentStore] = useState(null);
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
useEffect(() => {
Reps.TimeOfMove.forEach((time, index) => {
setTimeout(() => {
setCurrentStore(Reps.ScoreOfMove[index])
}, time * 1000)
})
},[])
return (
<div className="App">
<p>{currentScore}</p>
</div>
);
}
export default App;
This should work.
import React, {useEffect, useState} from 'react';
import './App.css';
function App() {
const [score, setScore] = useState('');
const Reps = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
};
useEffect(() => {
Reps.TimeOfMove.forEach((time, index) => {
const interval = setInterval(() => setScore(Reps.ScoreOfMove[index]), time * 1000);
return () => {
clearInterval(interval);
};
})
}, [])
return (
<div>
{score}
</div>
);
}
export default App;
here a solution in Vanilla JS, you can apply in React or where you want
This is a recursive solution.
const arrs = {
TimeOfMove: [1, 2.5, 3, 3.5, 4.5, 5, 6, 10, 12, 13, 14, 15.5],
ScoreOfMove: [60, 85, 42, 60, 70, 80, 90, 100, 90, 40, 0, 20],
}
const runTimer = (index) => {
if (index === arrs.TimeOfMove.length - 1) {
console.log('Timer is finished!')
return;
}
setTimeout(() => {
console.log(arrs.ScoreOfMove[index]);
runTimer(index + 1);
}, arrs.TimeOfMove[index] * 1000)
}
const INDEX_START = 0;
runTimer(INDEX_START);
Aditional, share codepen
https://codepen.io/niko20/pen/MWpryRB
if you want show text "score of move" in DOM can use useState of ReactJS and set score when timer run.
I have a JS object, I have been trying to output it as an HTML table. I have been trying to achieve that by looping through the object, appending the results to a string and putting it inside the table via innerHTML.
The header row is OK
The first data row is OK
However, the subsequent rows do not break of into a new row in the HTML table.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tr id="headeris">
</tr>
<tr id="duomenys">
</tr>
</table>
<script>
var AdenTalisman =
{
"Enchant" : ["+0","+1","+2","+3","+4","+5","+6","+7","+8","+9","+10"],
"P.Atk" : ["-","-", "-", "-", "-", 50, 80, 135, 180, 225, 270],
"M.Atk" : ["-","-", "-", "-", "-", 100, 150, 250, 360, 420, 490],
"P.Def" : ["-",5, 10, 10, 20, 30, 40, 60, 80, 120, 160],
"M.Def" : ["-",5, 10, 10, 30, 40, 60, 80, 120, 160, 200],
"Atk.Speed": ["-",10, 12, 15, 20, 25, 40, 70, 80, 90, 100],
"C.Speed" : ["-",10, 12, 15, 20, 25, 45, 75, 95, 110, 125],
"HP" : ["-",100, 120, 150, 180, 220, 260, 520, 640, 910, 1120],
"MP" : ["-", 30, 50, 70, 100, 130, 160, 320, 360, 430, 530],
"XP/SP" : ["-", "-", "-", "-", 10, 15, 20, 50, 50, 50, 50]
}
tableH = [];
tableR = [];
let header = '';
for (let k of Object.keys(AdenTalisman)) {
header = [];
header += k.padEnd(10);
tableH += `
<th> ${header} </th>
`
}
console.log(header);
document.getElementById('headeris').innerHTML = tableH;
for (let i = 0; i <= 10; i++) {
tableR += "</tr>"
console.log(tableR)
document.getElementById('duomenys').innerHTML += tableR;
var tableR = '';
tableR += `<tr>`
for (let k of Object.keys(AdenTalisman)) {
row = [];
row += AdenTalisman[k][i];
tableR += `
<td> ${row} </td>
`
}
}
</script>
</body>
</html>
document.getElementById('duomenys').innerHTML += tableR; will:
Convert the DOM of that element into a string of HTML source code
Append a new string to the end of that string
Convert the string into an HTML DOM
The first time you do that, the end tag for the <table> is missing, so it gets added automatically as error recovery.
The second time you do that you end up with something like:
<table>...</table><tr>...
and it is just broken.
If you are going to build a table with JavaScript either:
Build the entire thing (from <table> to </table> with everything inside) as a regular string then then set set some element's innerHTML to that string once and at the end. or
Use createElement, appendChild and friends instead.
Use thead and tbody elements
const AdenTalisman = {
"Enchant": ["+0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", "+8", "+9", "+10"],
"P.Atk": ["-", "-", "-", "-", "-", 50, 80, 135, 180, 225, 270],
"M.Atk": ["-", "-", "-", "-", "-", 100, 150, 250, 360, 420, 490],
"P.Def": ["-", 5, 10, 10, 20, 30, 40, 60, 80, 120, 160],
"M.Def": ["-", 5, 10, 10, 30, 40, 60, 80, 120, 160, 200],
"Atk.Speed": ["-", 10, 12, 15, 20, 25, 40, 70, 80, 90, 100],
"C.Speed": ["-", 10, 12, 15, 20, 25, 45, 75, 95, 110, 125],
"HP": ["-", 100, 120, 150, 180, 220, 260, 520, 640, 910, 1120],
"MP": ["-", 30, 50, 70, 100, 130, 160, 320, 360, 430, 530],
"XP/SP": ["-", "-", "-", "-", 10, 15, 20, 50, 50, 50, 50]
}
const EL_theadRow = document.querySelector("#headeris tr");
const EL_tbody = document.querySelector("#duomenys");
const ELNew = (sel, att) => Object.assign(document.createElement(sel), att || {});
Object.entries(AdenTalisman).forEach(([name, items]) => {
// Create THs for THEAD>TR
EL_theadRow.append(ELNew("th", {textContent: name}));
// Create TR for TBODY
const TR = ELNew("tr");
// Create TD for TBODY>TR
items.forEach((val) => TR.append(ELNew("td", {textContent: val})));
EL_tbody.append(TR);
});
<table>
<thead id="headeris"><tr></tr></thead>
<tbody id="duomenys"></tbody>
</table>
Try this
Change table to use thead and tbody as stated on Roko answer
<table>
<thead id="headeris">
</thead>
<tbody id="duomenys">
</tbody>
</table>
Change multi array looping like this
var tableR = '';
for (let i = 0; i <= 10; i++) {
tableR += `<tr>`
for (let k of Object.keys(AdenTalisman)) {
row = [];
row = AdenTalisman[k][i];
tableR += `
<td> ${row} </td>
`
}
tableR += `</tr>`
}
document.getElementById('duomenys').innerHTML += tableR;
var AdenTalisman = {
"Enchant": ["+0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", "+8", "+9", "+10"],
"P.Atk": ["-", "-", "-", "-", "-", 50, 80, 135, 180, 225, 270],
"M.Atk": ["-", "-", "-", "-", "-", 100, 150, 250, 360, 420, 490],
"P.Def": ["-", 5, 10, 10, 20, 30, 40, 60, 80, 120, 160],
"M.Def": ["-", 5, 10, 10, 30, 40, 60, 80, 120, 160, 200],
"Atk.Speed": ["-", 10, 12, 15, 20, 25, 40, 70, 80, 90, 100],
"C.Speed": ["-", 10, 12, 15, 20, 25, 45, 75, 95, 110, 125],
"HP": ["-", 100, 120, 150, 180, 220, 260, 520, 640, 910, 1120],
"MP": ["-", 30, 50, 70, 100, 130, 160, 320, 360, 430, 530],
"XP/SP": ["-", "-", "-", "-", 10, 15, 20, 50, 50, 50, 50]
}
tableH = [];
tableR = [];
let header = '';
for (let k of Object.keys(AdenTalisman)) {
header = [];
header += k.padEnd(10);
tableH += `
<th> ${header} </th>
`
}
document.getElementById('headeris').innerHTML = tableH;
var tableR = '';
for (let i = 0; i <= 10; i++) {
tableR += `<tr>`
for (let k of Object.keys(AdenTalisman)) {
row = [];
row = AdenTalisman[k][i];
tableR += `
<td> ${row} </td>
`
}
tableR += `</tr>`
}
document.getElementById('duomenys').innerHTML += tableR;
<table>
<thead id="headeris">
</thead>
<tbody id="duomenys">
</tbody>
</table>
Or you can do it like this:
const AT = {
"Enchant": ["+0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", "+8", "+9", "+10"],
"P.Atk": ["-", "-", "-", "-", "-", 50, 80, 135, 180, 225, 270],
"M.Atk": ["-", "-", "-", "-", "-", 100, 150, 250, 360, 420, 490],
"P.Def": ["-", 5, 10, 10, 20, 30, 40, 60, 80, 120, 160],
"M.Def": ["-", 5, 10, 10, 30, 40, 60, 80, 120, 160, 200],
"Atk.Speed": ["-", 10, 12, 15, 20, 25, 40, 70, 80, 90, 100],
"C.Speed": ["-", 10, 12, 15, 20, 25, 45, 75, 95, 110, 125],
"HP": ["-", 100, 120, 150, 180, 220, 260, 520, 640, 910, 1120],
"MP": ["-", 30, 50, 70, 100, 130, 160, 320, 360, 430, 530],
"XP/SP": ["-", "-", "-", "-", 10, 15, 20, 50, 50, 50, 50]
};
document.querySelector("table").innerHTML = Object.entries(AT).map(([k,v],i)=>
"<tr><th>"+k+"</th>"+(i?"<td>":"<th>")+v.join(i?"</td><td>":"</th><th>")+(i?"</td>":"</th>")+"</tr>"
).join("");
table {border:1px solid grey}
th,td {text-align:right; padding:4px}
tr:nth-child(even) {background-color:#ddd}
<table></table>
I have two arrays, one of them represents data, and the other one - intervals. Both are sorted and their start and end values match. I go through nested for loops to calculate the average of data points in a given interval. As a result, I end up with one data value for each interval. For smaller size arrays, < 100-500 length, these linear loops do the work, however, this approach becomes an issue with several thousand data points. Any recommendation will be appreciated.
Please see a simplified code below with a link to JSfiddle at the end
var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100],
DataArrayA = [];
for (i = 0; i < TimelineArray.length-1; i++) {
var dataPointsInGivenTimeInterval = [];
for (j = 0; j < DataArray.length; j++) {
if (DataArray[j] > TimelineArray[i] && DataArray[j] <= TimelineArray[i+1]) {
dataPointsInGivenTimeInterval.push(DataArray[j]);
}
};
if (dataPointsInGivenTimeInterval.length == 0) {
DataArrayA.push(null);
}
else {
var sumOfdataPoints = null;
for (k = 0; k < dataPointsInGivenTimeInterval.length; k++) {
sumOfdataPoints += dataPointsInGivenTimeInterval[k];
}
var avg = sumOfdataPoints / dataPointsInGivenTimeInterval.length;
DataArrayA.push(avg);
}
} // end for
console.log(TimelineArray);
console.log(DataArrayA);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
The console output is
[0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100]
[4.75, 15, 25.25, 36, null, 56.2, 64, 75, 89, 95]
Here is the code at JSfiddle - calculating average values for given intervals
Since the arrays are sorted, you can do it linearly with respect to the size of the timeline and data:
var timeline = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
data = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100];
var averages = new Array(timeline.length - 1);
for (var i = 0, j = 0; i < timeline.length; i++) {
var sum = 0,
items = 0;
for (; data[j] <= timeline[i]; j++) {
sum += data[j];
++items;
}
if(i) averages[i-1] = sum / items;
}
console.log(averages);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
You don't need to re-scan DataArray from the beginning on each iteration.
var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100];
var DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100];
var res = [], pos = 0;
TimelineArray.forEach(function(v, i) {
for(var sum = 0, n = 0; DataArray[pos] <= v; n++) {
sum += DataArray[pos++];
}
i && res.push(n ? sum / n : null);
});
console.log(res);
Not sure if it'll be any faster, but here's a crack at it in a different way:
var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100],
DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100],
DataArrayA = [];
function avg(arr){
if(arr!= null && arr.length > 0)
return arr.reduce(function(a, b){ return a+b;}, 0) / arr.length;
return null;
}
for(var i = 0; i < TimelineArray.length-1; i++){
var interval = [TimelineArray[i], TimelineArray[i+1]];
var data = DataArray.filter(function(a){ return a > interval[0] && a <= interval[1]});
DataArrayA.push(avg(data));
}
console.log(DataArrayA);
edit 1: removed a loop.
var dataAsArray = [
["Student", "# items sold", "$ earned"],
['Alice', 40, 40],
['Bob', 20, 20],
['Catherine', 10, 30],
['Danny', 5, 50],
['Eva', 20, 20],
['Felipe', 50, 25],
['Gwen', 7, 15],
['Henry', 25, 25]
];
I want to create rows and columns something like above for passing to the googles drawchart().
same thing i want dynamically
['Alice', 40, 40],
['Bob', 20, 20],
['Catherine', 10, 30],
['Danny', 5, 50],
['Eva', 20, 20],
['Felipe', 50, 25],
['Gwen', 7, 15],
['Henry', 25, 25]
I have also try the following code
for (var i = 0; i < usersTable.length; i++) {
tdata.addRow([usersTable[i].name, parseInt(usersTable[i].rank), parseInt(usersTable[i].age) ]);
}
I had the same issue and I used the following:
var tdata = new google.visualization.DataTable();
Then initialise headers of your table:
tdata.addColumn('string', 'User');
tdata.addColumn('number', 'Rank');
tdata.addColumn('number', 'Age');
Then loop throught your dynamic data and do the following inside your loop:
for (var i = 0; i < usersTable.length; i++) {
tdata.addRow([usersTable[i].name, parseInt(usersTable[i].rank), parseInt(usersTable[i].age) ]);
}
Then finally draw your Chart:
chart.draw(tdata, options);
I have found the solution by using push method
var dataset = [['month','purchase','sale']];
for(var i =0; i < datasetArray.length; i++){
dataset.push([datasetArray.mnt, datasetArray.purchase, datasetArray.sale]);
}
thanks.
Finding a proper title for this is rather hard for me.
Imagine a set of numbers:
$numbers = array(10, 12, 20, 24, 34, 38, 41, 48);
Then there is a specific amount of picks:
$picks = 6;
What i would like to do is generate an array that contains combinations of each $picks numbers, but those numbers must be contained in $numbers.
The final array result should contain all possible combinations of the values specified in $numbers, but without the order being of any importance (i.e. meaning that [1,2,3] is equal to [1,3,2]).
Any attempts to write the function myself failed because i don't even know what condition i could base my loop on.
function computeCombinations(array $numbers, $picks){
while(?){
}
return $results;
}
Due to a lack of maths skills i cannot wrap my head around how to write this and i lack the proper naming for this algorithm to search for it on the web or on stackoverflow.
Whether the function ends up as javascript or PHP is not of importance.
UPDATE
I have been able to write a function that produces the desired result, but with one restriction: there is no way to really know when all combinations have been found. Therefore i used a rather sloppy workaround - a total iterations counter which will throw me out of the loop. Of course that function is not usable for practical applications, but i post it so that readers may be better able to understand what it was that i wanted to achieve:
function computeCombinations(array $numbers, $pickCount){
$results=array();
$totalIterations=0;
while(true){
shuffle($numbers);
$picks=array_slice($numbers, 0, $pickCount);
asort($picks);
$results[implode('',$picks)]=$picks;
if($totalIterations++ > 10000000)
break;
}
return $results;
}
$out = computeCombinations(array(10, 20, 30, 40, 50, 60, 70, 80), 6);
foreach($out as $v){
echo implode(', ',$v)."\n";
}
Prints:
30, 40, 50, 60, 70, 80
10, 20, 40, 50, 60, 80
20, 30, 40, 50, 60, 80
10, 20, 40, 60, 70, 80
10, 40, 50, 60, 70, 80
20, 30, 50, 60, 70, 80
10, 20, 30, 40, 50, 70
10, 20, 30, 50, 60, 70
20, 30, 40, 60, 70, 80
10, 30, 40, 60, 70, 80
10, 30, 50, 60, 70, 80
10, 20, 30, 50, 60, 80
10, 20, 30, 40, 50, 60
10, 20, 30, 60, 70, 80
10, 30, 40, 50, 60, 70
10, 20, 50, 60, 70, 80
10, 20, 40, 50, 70, 80
10, 20, 30, 50, 70, 80
10, 20, 30, 40, 60, 70
10, 30, 40, 50, 60, 80
20, 30, 40, 50, 60, 70
10, 20, 30, 40, 60, 80
10, 20, 30, 40, 70, 80
20, 30, 40, 50, 70, 80
10, 30, 40, 50, 70, 80
10, 20, 40, 50, 60, 70
20, 40, 50, 60, 70, 80
10, 20, 30, 40, 50, 80
This is not a perfect solution, but anyway:
You can do this recursively:
Version 2:
function computeCombination(array $source,$picks,$startIndex=0,array $pad=array())
{
if ($picks<=0) {
return $pad;
} elseif ($picks>=count($source)-$startIndex) {
return array(array_merge($pad,array_slice($source,$startIndex)));
}
$result=array();
foreach (range($startIndex,count($source)-$picks) as $subStartIndex) {
$subPad=$pad;
$subPad[]=$source[$subStartIndex];
if (empty($pad)) {// to make the output look nice
$result=array_merge($result,computeCombination($source,$picks-1,$subStartIndex+1,$subPad));
} else {
$result=array_merge($result,array(computeCombination($source,$picks-1,$subStartIndex+1,$subPad)));
}
}
return $result;
}
print_r(computeCombination(array(1,2,3,4,5),2));
Online demo
The print_r output:
Array
(
[0] => Array
(
[0] => 1
[1] => 2
)
[1] => Array
(
[0] => 1
[1] => 3
)
[2] => Array
(
[0] => 1
[1] => 4
)
[3] => Array
(
[0] => 1
[1] => 5
)
[4] => Array
(
[0] => 2
[1] => 3
)
[5] => Array
(
[0] => 2
[1] => 4
)
[6] => Array
(
[0] => 2
[1] => 5
)
[7] => Array
(
[0] => 3
[1] => 4
)
[8] => Array
(
[0] => 3
[1] => 5
)
[9] => Array
(
[0] => 4
[1] => 5
)
)
(Old version 1)
function computeCombination(array $source,$picks,$startIndex=0,array $pad=array())
{
if ($picks<=0) {
return $pad;
} elseif ($picks>=count($source)-$startIndex) {
return array_merge($pad,array_slice($source,$startIndex));
}
$result=array();
foreach (range($startIndex,count($source)-$picks) as $subStartIndex) {
$subPad=$pad;
$subPad[]=$source[$subStartIndex];
$result=array_merge($result,array(computeCombination($source,$picks-1,$subStartIndex+1,$subPad)));
}
return $result;
}
print_r(computeCombination(array(1,2,3,4,5),2));
Online demo
EDIT
Here's another which is a bit more configurable:
<?php
$TOTAL = 7;
$MAX = 46;
$MIN = 1;
$numbers = array(10, 12, 20, 24, 34, 38, 41, 48);
for($i = 0; $i < $TOTAL; $i++) {
do {
$new_number = mt_rand($MIN,$MAX);
}
while(in_array($new_number, $numbers));
echo $new_number . "\n";
}
?>
Here's another:
<?php
// $numbers = range(1, 7);
$numbers = array(10, 12, 20, 24, 34, 38, 41, 48);
shuffle($numbers);
foreach ($numbers as $number) {
echo "$number ";
}
?>
And see if this will do the job:
I borrowed the example from The PHP.net Website - array_rand()
<?php
$input = array(10, 12, 20, 24, 34, 38, 41, 48);
$rand_keys = array_rand($input, 7);
echo $input[$rand_keys[0]] . "\n";
echo $input[$rand_keys[1]] . "\n";
echo $input[$rand_keys[2]] . "\n";
echo $input[$rand_keys[3]] . "\n";
echo $input[$rand_keys[4]] . "\n";
echo $input[$rand_keys[5]] . "\n";
echo $input[$rand_keys[6]] . "\n";
echo $input[$rand_keys[7]] . "\n";
?>