Looping to a specific index within a string - javascript

I'm currently doing a puzzle and am having trouble formulating my thoughts on how to do the following. Heres some code for some context on my thoughts (this isn't working yet)
const words = ['this', 'is', 'my', 'dog', 'bit', 'bite', 'every'];
const strings = ['thisis', 'thisisacat', 'thisisaduck', 'thisismy', 'thisismydog', 'bitevery'];
var count;
for (var i = 0 ; i < strings.length ; i++)
{
for (var j = 0; j <words.length; j++)
{
if(strings[i].indexOf(words[j]) !== -1)
{
count+=words[j].length;
}
}
}
Basically I want to first go to the word this check if it is in strings[j]. If it is then get the length of words[i], and go to the words[i]'th position inside strings[j] meaning I want the 'is' part of the 'thisis'. Basically I just want to test whether each element in strings can be represented by any amount of combos in words. This of course can be done with regular expressions, but I would like to use the current thought process that I have.
TLDR
With my current way, how can I check whether words in the words array exist within each element of strings(I am attempting this with indexOf), and if it is, go to the length of that words position meaning go to the position where i is in thisis. I realize that the way I am phrasing it it might be a bit verbose, but I'm not sure how else to phrase it. Any help is appreciated.
Example Run
We are at strings[i], now we check if any element in words is in strings[i]. Now this is in 'thisis', so add an index of four, since this has a length of four, to get to the 4th position and beyond of thisis, now we have isso loop again through the rest of words, now is is inside is, that means we have succesfully created a word from using some amount of words in the words array. Note, I actually don't want to delete the this from thisis, as I know modifying strings altogether is very costly in memory.
Another Run
Take thisismydog in strings. Let us iterate through words. this is inside thisismydog, so now go to the 4th onwards of thisismydog ( since this has a length of 4) namely now we consider ismydog. Now iterate again looking at the elements in words. We see is is there, so we go to the second element in ismydog, namely mydog. Since we reach the end of the word we can successfully conclude that thisismydog can indeed be represented by a combination of those elements within words.

Related

Should I include an if statement to prevent a redundant iteration in a loop?

You see, I've return this code to reverse the elements of an Array. This array takes two extreme elements and exchanges them like say [1,2,3,4] => [4,2,3,1] => [4,3,2,1]. However when there are odd number of elements there is a redundant iteration where it exchanges the middle element with the middle element itself. I know computers are a lot faster than say 100 years ago, but just in case would keeping my code as it is offset the efficiency gained by using an "if statement" to prevent that one extra iteration? You see I'm a newbie and wanted to know whether an if statement is more computationaly draining than a single extra iteration. Thank you in advance.
let arr = [1,2,3,4,5]
function reversearray(array){
for(let a=0; a < array.length-a; a++){
let total = array[array.length-a-1];
array[array.length-a-1] =array[a];
array[a]=total;
}
return array;
}
No, running an additional if statement for every array position to cover one case scenario is far more inefficient than allowing one "unnecessary" loop iteration.
Neither - make your loop run the correct number of times:
for(let a=0; a < Math.floor(array.length/2); a++){ …

JavaScript - adding spaces after push in empty array & one checkbox is free

Here's my codepen:
https://codepen.io/CwittleZ/pen/vdzazO?editors=1010
When you click on the meat selection, it gets pushed into an array and then displayed, but there's no space between selections. How would I go about adding that space?
function meatSelected() {
var meat = [];
var meatChecked = document.querySelectorAll(
"input[name=meat_options]:checked"
);
for (var i = 0; i < meatChecked.length; i++) {
meat.push(meatChecked[i].value);
}
console.log(meat);
document.getElementById("meat").innerHTML = meat;
}
Also, I need one of the meats to be free, but anything over will be extra. I don't know how or where to add that 'if meat checked is > 1, all other meats will be an additional $1 each.' Is there somehow a way to access the function meatSelected for that purpose? I'm just starting out with JavaScript, so please no jQuery and simple terms if possible, even if it is a longer code. I just want to be able to understand why it works.
if (document.getElementById("pepperoni").checked) {
add += 1;
}
if (document.getElementById("sausage").checked) {
add += 1;
}
if (document.getElementById("canadian_bacon").checked) {
add += 1;
}
if (document.getElementById("ground_beef").checked) {
add += 1;
}
if (document.getElementById("anchovy").checked) {
add += 1;
}
if (document.getElementById("chicken").checked) {
add += 1;
}
The answer is in the line 83 in JavaScript part of your example. In line 77, you made an array of possible meats. Then, you just used this array and attached it to innerHTML as it is, so that the browser has to make it a string. Unfortunately, it doesn't care about spaces.
So, just change that line to this:
document.getElementById("meat").innerHTML = meat.join(", ");
It will use your already made array and convert it directly into string, with ", " between each of its children.
And to your second question, there are more possible solutions, I've implemented the easiest one in this codepen: https://codepen.io/anon/pen/ddqqyY?editors=1010.
Just sum up the number of already selected meats and if it's larger than zero, subtract 1 from your total.
I'd wrap each one of your selections in a "span", and add a margin after. You're using innerHTML, so you can just do it that way. It'll provide more flexibility than trying to style the plain-text.
document.getElementById("meat").innerHTML = meat.map(m => ` ${m}`);
here is your codepen that is modified https://codepen.io/jayas/pen/bLxjXo?editors=1010
edit as per suggestion
The ${m} together with the enclosing ticks `` used in the statement is called a template literal. Template literals can contain placeholders
and these are indicated by the dollar sign and curly braces ${}.
[].map(callBackFunc) used above is a method that creates a new array with each element being the result of the callback function.

Creating arrays on condition in javascript

This has been eating me away. Check CodePen here. I have a function that adds elements to a ruler. Call expose.init(lengthOfPeriod) with an integer to set the length of each period in the ruler. Call expose.addAction(time, team) with an integer and a string == 'HOME' || 'AWAY' to place an action in the ruler.
When the screen is resized, I want something to happen to the elements in the ruler that touch each other (basically collapse into a group).
I have a function 'detectOverlap' that takes 2 params and determines if they are touching or not. I also have a function in the resize event handler that populates an array 'allTouching' with all the elements in the ruler that are touching each other at each resize.
if (actionArray.length > 1) { //don't run if there's only one element in the page
actionArray.reduce(function (prev, next) {
if (detectOverlap(prev, next)) {
if (allTouching.indexOf(prev, next) === -1) allTouching.push(prev, next);
}
return next;
});
If actions are touching each other, I need them to collapse into groups. In order to do this, I need to create an array for each group of actions touching each other. However, I haven't been able to make this happen so far.
Here's some pseudo code:
for (i = 0; i < allTouching.length; i++) {
if (detectOverlap(allTouching[0], alltouching) {
touchingGroup[i] = new Array(allTouching[0], all other elements touched by 0);
do not include any element more than once in touchingGroup[i];
do not include any similar arrays (same elements) in allGroups;
allGroups.push(touchingGroup[i]);
}
}
In short, this would need to loop for all the elements in the allTouching array, and create a new touchingGroup[n] for each new group of actions that touch each other.
This sounds simple in my head, and I'm sure there must be a way to do it without code getting overly complex, but I haven't found it yet.
Any feedback would be appreciated.
It seems your question is only about the grouping, so I will ignore the visualisation aspect and assume that the function detectOverlap is correct.
Then you could create the groups in one for loop. In this snippet I have added simplistic sample data and a mock detectOverlap function that will return true when its two arguments are the same (just for the purpose of the snippet):
// Simplistic mock data and function, just to make the snippet work
var actionArray = [1, 1, 3, 3, 3, 8, 9];
function detectOverlap(a, b) { return a === b; }
// Actual code:
var allGroups = [];
var start = 0;
for (var i = 1; i <= actionArray.length; i++) {
if (i >= actionArray.length || !detectOverlap(actionArray[i-1], actionArray[i])) {
if (i - start > 1) // Remove this condition if you want singletons as well
allGroups.push(actionArray.slice(start, i));
start = i;
}
}
console.log(JSON.stringify(allGroups));
Explanation
The variable start is used as an index in the array, from where the most recently found group should start. That group is not yet actually created, since we do not know where it ends, and so I will call this the "undecided" group. start is initialised at 0 to indicate that the first group will start there.
The loop iterates over the array, but starting at 1. In each iteration it decides whether the "undecided" group (started at start) is complete. The group is considered complete when there is no overlap between the previous and the current element of the array. In that case the previous element is the last element of the "undecided" group. The elements for that group are copied from the array with slice. Note that the second argument of slice is the index of the first element that should not be part of the group. Now that group is stored, and start is put at the current index, where the next (and only) "undecided" group should start.
But as long as the two elements do overlap, no new group should be created (that is why the condition has a !). Instead start remains unchanged, and so this "undecided", "unclosed" group is getting bigger in size.
There is an if just before that slice, which prevents the creation of groups that only contain one element. If you remove that if, then also single elements will be isolated in their own "singleton" groups.
The loop will go up to and including arrayAction.length: this is unusual, since that makes the last i an invalid index. But it is useful, since in that case we still want to finish up the last group that is still "ongoing". So in that case i >= arrayAction.length will be true, and so the detectOverlap function will not be called (because the if condition is already known to be true). The if block will be entered and the final group will be created.

arr.splice() is timing out in loop - better way to replace arr[i]?

So I am having an issue with my solution, and I may be entirely off on what needs to be done. I keep timing out which makes me believe I have the .splice() in an incorrect location.
The problem:
You are given an array of integers. On each move you are allowed to increase exactly one of its element by one. Find the minimal number of moves required to obtain a strictly increasing sequence from the input.
Example
For inputArray = [1, 1, 1], the output should be
arrayChange(inputArray) = 3.
My Pseudo code
First check and see if the current index is greater than the next index. If not, continue check through the entire loop. If so, add one to the next index and test again until true. If you increment the next index by one, add one to a variable "moves". Return moves
function arrayChange(inputArray) {
for( var i = 0; i < inputArray.length; i++){
var addition = (inputArray[i+1]+1)
if(inputArray[i] >= inputArray[i+1]){
inputArray.splice(i,0, addition);
}
}
return inputArray;
}
My Error:
Execution time limit exceeded on test 1: Program exceeded the execution time limit. Make sure that it completes execution in a few seconds for any possible input.
Why your code fails:
for( var i = 0; i < inputArray.length; i++){//iterate until reaching end of array
var addition =(inputArray[i+1]+1);
if(inputArray[i] >= inputArray[i+1]){ //if its not increasing
inputArray.splice(i,0, addition);
}
}
Lets examine a sample input:
arrayChange([1,1]);
So inputArray[i] is 1, and inputArray[i+1] is 1.
Therefore it will go into the if, as 1>=1. So it will add 1+1 into the array,but not at the end but at i, so at position 0. It will look like this:
[2,1,1]
The loop will go on:
[2,2,2....,1,1]
It will never end.
To make it work, you must stop at array.length-1 :
for( var i = 0; i < inputArray.length-1; i++){
and you must insert at the right index,and also remove one:
inputArray.splice(i+1,1,addition);
Non array changing approach:
function numchanges(array){
var before=array[0],counter=0;
for(var i=1;i<array.length;i++){
if(before>=array[i]){
//we need to change array[i] to before+1, so:
counter+=(++before)-array[i];
}else{
before=array[i];
}
}
return counter;
}
console.log(numchanges([1,1,1]));//should return 3
How it works:
A proper strictly monotonically increasing function would have values like this:
[1,2,3,4,5,10]
So it might at least go one up, or it jumps up. So lets take one random array, and its valid counterpart:
[1,1,3,4,5,-1]
[1,2,3,4,5,6]
So the changes needed:
[0,1,0,0,0,7] => 8
So the upper code keeps the valid number ( before ) and the needed change while iterating from left to right. current starts with the first array item:
before=array[0];//1
But we dont need to change the first array element, so we start at i=1.If this number is valid, so
before<array[i]
we just go on:
before=array[i];
i++;//due the for loop
If not, its not valid and we need a correction.
result+=before+1-array[i];
So if the last was 5 (=before) and now weve got -10 (=array[i]), we need to correct it to 6 (=before+1);
result+=6--10//==16
So we need another 16 corrections...

An algorithm to tell how many distinct, leading characters are necessary to discern a word from a list?

So if you have a list of 50 words, and you want to see how deep into a word a reader must look to be able to count all of the unique words, how would you go about doing that?
I'm basically thinking about loading characters into an array, one-by-one, and then comparing them. There are so many characters and so many arrays to compare, though. I wonder what's the most efficient way, if there's already an efficient way out there?
I'm trying to use Javascript, right now.
var words = [sort(prompt("Please, insert the word list", "default value in the text field"););];
var encr_int: Number=0;
for (i=0, j=0, maxdif=0; j < word.length; i++) {
if(word[j].text.charAt(i) == word[j+1].text.charAt(i) AND i > maxdif) {
maxdif = i;
}
else if(word[j].text.charAt(i) != word[j+1].text.charAt(i) {
j+=1;
}
else if(word[j].text.charAt(i) == "") {
i = 0;
}
}
document.write(maxdif);
Above is my effort at writing the program based on the first answer.
A more efficient approach might be to store your set of words in a trie structure rather than a list. This is a hierarchical structure where each node contains the prefix characters of its children. This means that you don't have to compare against all words - once a certain prefix is found to match words without that prefix need are eliminated.
Although for 50 words speed is not likely to be an issue, the trie will enable you to minimise the number of character comparisons needed and you can keep track of the character count as you recurse down the hierarchy.
If absolute efficiency is a requirement then the precise way in which you organise the trie might become important for example it could be organised to be efficient taking account of the actual statistics of the searches being made against it.
Sort the list and then iterate through it, comparing each word with the subsequent word. Compare with a routine that tells you how many characters had to be checked before a difference was found. Keep track of the maximum "depth" as you go.
edit — a function to tell you the "similarity" of two words based on leading characters:
function similarity(w1, w2) {
var i, l = Math.min(w1.length, w2.length);
for (i = 0; i < l; ++i)
if (w1[i] !== w2[i]) break;
return i;
}

Categories

Resources