I'd like to build a text string by inserting the characters at random, but in place order (as a kind of effect) . So far I've got:
// make a string and an array
var input = "Hello, world!",
output = [];
// split the string
input = input.split('');
My idea is then to call this
function addAnElement(){
// check if there are any left
if(input.length){
// pick an element at random
var rand = Math.floor(Math.random() * input.length);
// remove it, so we don't call it again
var element = input.splice(rand,1);
// insert it
output[rand] = element;
// use the string returned as new innerHTML, for example
return output.join('');
// repeat until finished
setTimeout(addAnElement,5);
}
}
I'm hoping this would return something like:
'e'
'er'
...
'Hel, or!'
...
'Helo, Word!'
... and finally ...
'Hello, World!'
The problem, of course, is that the array is re-indexed when spliced - and this yields gibberish. I think the answer must be to link the elements to their positions in input and then insert them intact, sorting by key if necessary before returning.
How do I do this?
How about something like this:
var input = 'Hello world',
inputIndexes = [],
output = [];
for (var i = 0; i < input.length; i++) {
inputIndexes[i] = i;
};
function addAnElement() {
if (inputIndexes.length) {
var rand = Math.floor(Math.random() * inputIndexes.length);
var element = inputIndexes.splice(rand, 1);
output[element] = input[element];
//console.log(output.join(' '));
document.getElementById('text').innerHTML = output.join(' ');
setTimeout(addAnElement, 2000);
}
}
addAnElement();
http://jsfiddle.net/fg2ybz8j/
You can avoid it by not using splice. Instead, clear an entry when you've used it, and keep a count of the entries you've cleared.
E.g.:
var entriesLeft = input.length;
function addAnElement(){
// pick an element at random, re-picking if we've already
// picked that one
var rand;
do {
rand = Math.floor(Math.random() * input.length);
}
while (!input[rand]);
// get it
var element = input[rand];
// clear it, so we don't use it again
input[rand] = undefined;
// insert it
output[rand] = element;
// repeat until finished
if (--entriesLeft) {
setTimeout(addAnElement,5);
}
// use the string returned as new innerHTML, for example
return output.join('');
}
Of course, that loop picking a random number might go on a while for the last couple of characters. If you're worried about that, you can create a randomized array of the indexes to use up-front. This question and its answers address doing that.
Live Example:
var input = "Hello, there!".split("");
var output = [];
var entriesLeft = input.length;
function addAnElement() {
// pick an element at random, re-picking if we've already
// picked that one
var rand;
do {
rand = Math.floor(Math.random() * input.length);
}
while (!input[rand]);
// get it
var element = input[rand];
// clear it, so we don't use it again
input[rand] = undefined;
// insert it
output[rand] = element;
// repeat until finished
if (--entriesLeft) {
setTimeout(addAnElement, 5);
}
// use the string returned as new innerHTML, for example
document.body.innerHTML = output.join('');
}
addAnElement();
Side note: Notice how I've moved the call to setTimeout before the return. return exits the function, so there wouldn't be any call to setTimeout. That said, I'm confused by the need for the return output.join(''); at all; all calls but the first are via the timer mechanism, which doesn't care about the return value. In the live example, I've replaced that return with an assignment to document.body.innerHTML.
Here's a demonstration of the method that shuffles an array of indexes instead. It uses the shuffle method from this answer, but I'm not saying that's necessarily the best shuffle method.
function shuffle(array) {
var tmp, current, top = array.length;
if (top)
while (--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
var input = "Hello, there".split("");
var output = [];
var indexes = input.map(function(entry, index) {
return index;
});
shuffle(indexes);
var n = 0;
function addAnElement() {
// get this index
var index = indexes[n];
// get this loop's element
var element = input[index];
// insert it
output[index] = element;
// repeat until finished
if (++n < indexes.length) {
setTimeout(addAnElement, 5);
}
// use the string returned as new innerHTML, for example
document.body.innerHTML = output.join("");
}
addAnElement();
Related
I am trying to make a sorting visualizer. But when I am creating a array using following code, every time when I create a new array I am getting the same array as previous one! I have to refresh the page to get a new array. What will I have to do in order to get different array without refreshing through browser.
let sortingMethod = "";
let array = [];
function between(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function createArray() {
for(let i = 0; i < 20; i++) {
array.push(between(20));
}
let arena = document.querySelector(".arena");
arena.innerHTML = '';
for(let i = 0; i < 20; i++) {
let element = document.createElement('div');
element.setAttribute('class', 'element');
console.log(array[i]);
element.style.height = (array[i] * 20) + "px";
arena.appendChild(element);
}
//console.log("created");
}
let create = document.getElementById("create");
create.addEventListener('click', createArray);
You are never clearing your array. So, each time you call createArray, new values are just appended to the end of the already filled array, but you only use first 20 values each time.
To solve your problem, just write this part of code let array = []; inside your createArray function.
I have a function that I have modified to get a string (which consists of zeros and ones only).
The string (timesheetcoldata):
100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000
The string items (the numbers one and zero) will change every time the function is run.
It will always be the same length.
I have made the string above easier to see what I am trying to achieve.
I want to return the first character and then every 24th character (as in the variable colsCount in the function).
so, in the example above, it would return something like: 111111
I then want to convert these characters to numbers (something like [1, 1, 1, 1, 1, 1]).
I then want to sum these number together (so it would return, in the example: 6).
I then want to check if the returned number matches the variable: rowsCount
or true if it does, false if it does not.
My function:
$("#J_timingSubmit").click(function(ev){
var sheetStates = sheet.getSheetStates();
var rowsCount = 6;
var colsCount = 24;
var timesheetrowsdata = "";
var timesheetcoldata = "";
for(var row= 0, rowStates=[]; row<rowsCount; ++row){
rowStates = sheetStates[row];
timesheetrowsdata += rowStates+(row==rowsCount-1?'':',');
}
timesheetcoldata = timesheetrowsdata.replace(/,/g, '');
console.log(timesheetcoldata);
});
Thank you very much to both Rajesh and MauriceNino (and all other contributers).
With their code I was able to come up with the following working function:
$("#J_timingSubmit").click(function(ev){
var sheetStates = sheet.getSheetStates();
var rowsCount = 6;
var timesheetrowsdata = "";
var timesheetcoldata = "";
for(var row= 0, rowStates=[]; row<rowsCount; ++row){
rowStates = sheetStates[row];
timesheetrowsdata += rowStates+(row==rowsCount-1?'':',');
}
timesheetcoldata = timesheetrowsdata.replace(/,/g, '');
var count = 0;
var list = [];
for(var i = 0; i< timesheetcoldata.length; i+=24) {
const num1 = Number(timesheetcoldata.charAt(i));
list.push(num1);
count += num1;
}
let isSameAsRowsCount = count == rowsCount;
console.log('Is Same? ', isSameAsRowsCount);
});
You can always rely on traditional for for such action. Using functional operations can be more readable but will be more time consuming(though not by much).
You can try this simple algo:
Create a list that will hold all numbers and a count variable to hold sum.
Loop over string. As string is fixed, you can set the increment factor to the count(24).
Convert the character at given index and save it in a variable.
Push this variable in list and also compute sum at every interval.
At the end of this loop, you have both values.
var string = '100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000';
var count = 0;
var list = [];
for(var i = 0; i< string.length; i+=24) {
const num1 = Number(string.charAt(i));
list.push(num1);
count += num1;
}
console.log(list, count)
Here is a step by step explanation, on what to do.
Use match() to get every nth char
Use map() to convert your array elements
Use reduce() to sum your array elements
Everything needed to say is included in code comments:
const testData = '100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000';
// Step 1) Create array of numbers from string
const dataArr = testData.match(/.{1,24}/g) // Split on every 24th char
.map(s => Number(s[0])) // Only take the first char as a Number
console.log(dataArr);
// Step 2) Sum array Numbers
let dataSum = dataArr.reduce((a, b) => a + b); // Add up all numbers
console.log(dataSum);
// Step 3) Compare your variables
let rowsCount = 123; // Your Test variable
let isSameAsRowsCount = dataSum == rowsCount;
console.log('Is Same? ', isSameAsRowsCount);
As #Jaromanda mentioned, you can use the following to done this.
const string = '100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000100000000000000000000000';
const value = string.split('').filter((e,i)=> !(i%24)).reduce((acc,cur)=> acc+ (+cur), 0);
console.log(value);
In the size() function, I have used split then finding the size of the array. Is there any other way or logic to find the size of the string separated by hyphens(---) other than split.
var Stack = function(){
this.callStack='';
}
Stack.prototype.push = function(val){
if(this.callStack==''){
this.callStack = this.callStack.concat(val);
}else {
this.callStack = this.callStack.concat('---', val);
}
}
Stack.prototype.pop = function(){
this.removeThis = this.callStack.lastIndexOf(('---'));
this.str = this.callStack.slice(this.removeThis+3);
this.callStack = this.callStack.substring(0, this.callStack.lastIndexOf('---'));
return this.callStack;
}
Stack.prototype.size = function(){
var sizes = this.callStack.split('---');
return sizes.length;
}
//This will tell the latest element inserted in the stack:
Stack.prototype.peek= function(){
var peekabu = this.callStack.slice(this.callStack.lastIndexOf('---')+3);
return peekabu;
}
var stackInst = new Stack();
stackInst.push('Ankit');
stackInst.push('Ashu');
stackInst.push('Ash');
stackInst.push('Pikachu');
console.log('Size of the Stack is:', stackInst.size());
...without using split or anything outside of strings
That's an odd restriction.
You could use replace to replace all non-hyphens, and take the length of the result:
return this.callStack.replace(/[^-]/g, '').length;
If you mean the number of --- occurrences, not just the number of hyphens, divide by 3 (naturally this assumes there won't be other hyphens in there):
return this.callStack.replace(/[^-]/g, '').length / 3;
But to be certain of only counting ---, you could pass a callback to replace:
let size = 0;
this.callStack.replace(/---/g, function(m) {
++size;
});
return size;
But again, it's an odd restriction, and these are odd solutions as a result.
I'm am working on a script to count the number of times a certain string (in this case, coordinates) occur in a string. I currently have the following:
if (game_data.mode == "incomings") {
var table = document.getElementById("incomings_table");
var rows = table.getElementsByTagName("tr");
var headers = rows[0].getElementsByTagName("th");
var allcoord = new Array(rows.length);
for (i = 1; i < rows.length - 1; i++) {
cells = rows[i].getElementsByTagName("td");
var contents = (cells[1].textContent);
contents = contents.split(/\(/);
contents = contents[contents.length - 1].split(/\)/)[0];
allcoord[i - 1] = contents
}}
So now I have my variable allcoords. If I alert this, it looks like this (depending on the number of coordinates there are on the page):
584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519,,
My goal is that, for each coordinate, it saves how many times that coordinate occurs on the page. I can't seem to figure out how to do so though, so any help would be much appreciated.
you can use regular expression like this
"124682895579215".match(/2/g).length;
It will give you the count of expression
So you can pick say first co-ordinate 584 while iterating then you can use the regular expression to check the count
and just additional information
You can use indexOf to check if string present
I would not handle this as strings. Like, the table, is an array of arrays and those strings you're looking for, are in fact coordinates. Soooo... I made a fiddle, but let's look at the code first.
// Let's have a type for the coordinates
function Coords(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
return this;
}
// So that we can extend the type as we need
Coords.prototype.CountMatches = function(arr){
// Counts how many times the given Coordinates occur in the given array
var count = 0;
for(var i = 0; i < arr.length; i++){
if (this.x === arr[i].x && this.y === arr[i].y) count++;
}
return count;
};
// Also, since we decided to handle coordinates
// let's have a method to convert a string to Coords.
String.prototype.ToCoords = function () {
var matches = this.match(/[(]{1}(\d+)[|]{1}(\d+)[)]{1}/);
var nums = [];
for (var i = 1; i < matches.length; i++) {
nums.push(matches[i]);
}
return new Coords(nums[0], nums[1]);
};
// Now that we have our types set, let's have an array to store all the coords
var allCoords = [];
// And some fake data for the 'table'
var rows = [
{ td: '04.shovel (633|455) C46' },
{ td: 'Fruits kata misdragingen (590|519)' },
{ td: 'monster magnet (665|506) C56' },
{ td: 'slayer (660|496) C46' },
{ td: 'Fruits kata misdragingen (590|517)' }
];
// Just like you did, we loop through the 'table'
for (var i = 0; i < rows.length; i++) {
var td = rows[i].td; //<-this would be your td text content
// Once we get the string from first td, we use String.prototype.ToCoords
// to convert it to type Coords
allCoords.push(td.ToCoords());
}
// Now we have all the data set up, so let's have one test coordinate
var testCoords = new Coords(660, 496);
// And we use the Coords.prototype.CountMatches on the allCoords array to get the count
var count = testCoords.CountMatches(allCoords);
// count = 1, since slayer is in there
Use the .indexOf() method and count every time it does not return -1, and on each increment pass the previous index value +1 as the new start parameter.
You can use the split method.
string.split('517,594').length-1 would return 2
(where string is '584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519')
I am getting a random generated number between one and 10 from getRandom(1,10), but i do not want the same number twice.
To prevent that, I am saving the number I get inside an array used.
Now I want to check if the new number I get already is inside that array.
If not continue going,
if it is, then start over (get new number etc.).
What I am missing right now is the part where it should start over. Or should this work?
jQuery(document).ready(function($){
var i=0;
while (i<21){
var used = new Array(20);
for(a=0; a<20; a++) {
var number = getRandom(1, 20);
used[a] = number;
}
var tf = inArray(number,used);
//Check if number is inside the
if(tf==false){
//If not
i++;
}else{
//If it is
i--;
}
}
function inArray(Item,arr) {
for(p=0;p<arr.length;p++) {
if (arr[p]==Item) {
return true;
}
}
return false;
}
});
// create pool of numbers
var pool = [];
for (var i=1; i<=20; i++)
pool.push(i);
// pop off a random element of the array
var some_random_number = pool.splice(Math.floor(Math.random()*pool.length), 1)[0]
// repeat until pool is empty.