Add indexes of all occurrences of character in a string to array - javascript

I'm trying to add all of the indexes of a specific character to an array from a string.
I've got the following code, but I've had to restart my browser about 10 times because it doesn't work.
var xPositions = new Array();
var startPos = 0;
var string = "abcdexabcdexabcdexabcdexabcdexabcdexabcdex";
while (true) {
var currentIndex = string.indexOf("x", startPos);
if (currentIndex == -1) {
break;
}
xPositions.push(currentIndex);
startPos = currentIndex;
}
I thought about iterating forever until there are no more occurrences of the character, and then break.
Any help/suggestions appreciated.

Try
var currentIndex = string.indexOf("x", startPos+1);
I think you're getting the same current index over and over. "indexOf" begins its search at the index you specify, so you must increment it relative to the last find.
For future reference, you may consider trying to use a debugger with breakpoints, problems like this become relatively easy to spot (even just doing a few console.log's of relevant data can make mincemeat out of this type of bug - it's hard to always perfectly understand how a function you've never used before will work, there's no shame in seeing if it's behavior matches your expectations).

Related

Finding a valid substring

I am a bit puzzled by one exercise I recently came across with.
It seems like an easy task and I've put my solution but it turned out it didn't pass all the tests :D
In the example, I've found two example substrings:
Input: S = "(()("
Output: 2
Explanation: The longest valid
substring is "()". Length = 2.
and
Input: S = "()(())("
Output: 6
Explanation: The longest valid
substring is "()(())". Length = 6.
at the first glance, everything is clear.
I came up with my solution:
class Solution {
findMaxLen(s) {
if (!s || !s.length) throw new Error('Invalid input value provided')
let openIndex = null
let closingIndex = null
for (let i = 0; i < s.length; i++) {
if (s[i] == '(' && !openIndex) openIndex = i + 1
if (s[i] == ')') closingIndex = i + 1
}
if(!closingIndex || !openIndex) throw new Error('Invalid substring')
return closingIndex - openIndex + 1
}
}
So, my solution should solve the issue of trying to find The longest substring with the opening and closing parentheses.
But it failed the test with an input value: (((()
Where the correct answer is 2 and my output is 5
Is this (((() different from ()(())( one provided in the example?
I suppose I do not wholly understand the idea of what the substring is or something...
This pseudocode should work. Some bugs or edge cases might have loose ends as I just wrote this here on the fly. Feel free to test it and point out the misses.
helper_stack = null
max_valid_len = 0
running_len = 0
for i=0 to input_s.length:
if helper_stack.length == 0:
if input_s[i] == ')':
running_len = 0
continue
else:
helper_stack.push('(')
else:
if input_s[i] == '(':
helper_stack.push('(')
else:
helper_stack.pop()
running_len += 2
if running_len > max_valid_len:
max_valid_len = running_len
EDIT: Explanation
With your logic, you are not keeping track of order of opening and closing of brackets, which is important. If a closing bracket precedes open, string becomes invaid by default. Hence, using stack makes sense here.
If ever we encounter a closing bracket before open, we restart from that point. Hence, we set the running_len = 0. For every encounter of closing bracket, if an open bracket is there to balance it, we just pop it off, and since its a pair (of chars, when we consider length of string), running_len += 2 is done.
With little modification, we can even reproduce max_valid_substring if needed. However, in our case, we could even use just an integer instead of helper_stack. For every push('(') operation, just do var += 1, and var -= 1 for pop and that should also do the trick. Note that here, we are not explicitly using stack, but this is still conceptually LIFO = last in first out which is basically, stack.

Arrays are causing me problems

So. Started arrays. Yeah went as well as the loops did. And as a result, I need help.
/*jshint multistr:true */
var text = "Yo yo yo, what's / good fam. My name is / Caleb, my dude.";
var myName = "Caleb"
var hits = []
for(var i = 0; i >= text.length; i++){
if(text[i] === 'C') {
}
for(var j = i; i <= i + myName.length; i++){
}
}
That is the exact code that I have. Now, What it needs to do is search for my name within the confines of the text string. Only problem is that its saying that "It looks like your second 'for' loop isn't pushing values to the hits array. Make sure it's working properly and that myName's text appears somewhere in the text variable." This is a CodeAcademy project. I'm just not understanding. If someone could help me with this, I would really appreciate it.
Thanks!
First of all make sure you have all the semicolons right. Also, add some action in case the loop gets a result!
Also, i don't think you have defined var j, did you?
Finally - if it's asking u to push some values into hits array, then use this push method:
hits.push();
To help u i'd need deeper understanding of the task itself. what did u have to do, what were u starting with?
Edit:
var myName = "Caleb"; // define myName before text so it can be used in text
var text = "Yo yo yo, what's / good fam. My name is / "+myName+", my dude."; // define text and use myName variable between two strings, connected with +
var hits = []; // define hits array
for(var i = 0; i < text.length; i++) { //start loop, make sure second parameter is not infinite or it would crash your browser
if(text[i] === 'C') { // if found i that corresponds with 'C'
var letterLocation = i; // set variable letterLocation with value of 'C' position
hits.push(i); // add the location number to hits array with .push method
};
};
console.log(hits); // display hits array in console
Here's some working code for you, just follow the task and change whatever is necessary - hope it helps.
Generally - i changed the order of variables, so that u can use myName in text, also made the for loop print out the position of letter C and push this value into the hits array. Is that what u meant?

Why Runtime error if input array element are parsed to integer altogether in javascript?

I was working on counting sort1 problem on hackerrank. I am using JavaScript to solve the problem.
Standard input is providing a number and an array which I was reading like this
var inp = input.split('\n')
var n = parseInt(inp[0]); //Number of elements
var ar = inp[1].split(' ').map(function(item){
return parseInt(item);
}); //Array of numbers.
I was using above code in almost all of my solutions, it always worked.
Then I process the above array ar in for loop which is giving runtime error in one of the test cases(last testcase).
for(var i = 0; i < n; i++) {
var number = ar[i];
//more code
}
But if I don't parse elements of the array using map function but parse them later in for loop, one by one, I don't get any error.
var ar = in[1].split(' '); //Array of numbers in string format
for(var i = 0; i < n; i++) {
var number = parseInt(ar[i]);
//more code
}
Can Anyone explain Why?
in is a keyword, and you are trying to use it as a variable. I'm not sure why it says "Runtime Error", since this is actually a parsing error. Once renamed to something else, I could run the first two paragraphs error-free.
The only problem I remember having on Hackerrank that the .split() method often gave an empty string ("") as the last element of the array. Probably that's why you failed on the last test case.
Make your logic like:
if(arr[i] !== "")
// perform operations
else
break;
Also, you can't use in as a identifier because it is a reserved keyword.

MongoDB: cannot iterate through all data with cursor (because data is corrupted)

Update:
The story is off-topic and the title misleading. The problem is caused by corrupted data set, not cursors, or MongoDB itself. But I would rather like to leave this thread here than to delete it, for that it might help other desperate people.
=== Original story starts here ===
It all starts here: MongoDB: cannot use a cursor to iterate through all the data
I was trying to iterate through a cursor in Java, and it fails because my collection has too many records(~250M). I tried to allocate a new cursor and use cursor.skip to jump back in when the cursor gets timed out but cursor.skip itself times out.
#mnemosyn pointed out the right way for me: break the job into two stages: In the first stage, use a projected cursor to pull only the monotonic _id's of the records. Record the _id's, and then store it somewhere else as "checkpoints". During the second stage, I can then access any chunk of records as a checkpoint recorded.
So I wrote a javascript like this:
db=connect("localhost/twitter");
db.jobScheduler.drop();
for(var i = 0;i<16;++i)
{
db.jobScheduler.save({_id:"s"+i,jobs:[]});
}
var c = db.tweets.find({},{_id:1}).sort({_id:1});
var totalCount = c.count();
var currentBatchSize = 0;
var currentNum = 0;
var currentShard = 0;
var startTid = 0;
var endTid = 0;
var currentTid = 0;
while(true)
{
while(c.hasNext())
{
var doc = c.next()
currentTid = doc._id;
if(currentBatchSize == 0)
{
startTid = doc._id;
}
++currentNum;
++currentBatchSize;
if(currentBatchSize == 50000)
{
currentBatchSize = 0;
endTid = doc._id;
db.jobScheduler.update(
{_id:"s"+currentShard},
{$push:{jobs:[startTid,endTid]}});
currentShard = (currentShard+1)%16;
print(currentNum+"/"+totalCount+"("+currentNum*100/totalCount+"%)");
print("["+startTid+","+endTid+"]");
}
}
if(currentNum != totalCount){
var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
print("Cursor resetted....");
}else
break;
}
if(currentBatchSize != 0)
{
currentBatchSize = 0;
endTid = doc._id;
db.jobScheduler.update(
{_id:"s"+currentShard},
{$push:{jobs:[startTid,endTid]}});
currentShard = (currentShard+1)%16;
}
Considering that simply pulling _id only would still result in timeout, I added a guard like this:
if(currentNum != totalCount){
var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
print("Cursor resetted....");
}else
break;
because when the cursor times out, I don't get an exception but a false cursor.hasNext().
Since I already recorded currentTid when iterating through them, using the range query var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1}); will put me back in position, theoretically. However the poor little program end up like this:
[337242463750201340,345999466677010400]
21800000/253531208(8.598546968624076%)
[345999469818544100,346244305876295700]
Cursor resetted....
Cursor resetted....
Cursor resetted....
It seems to be stuck at the first occurrence of cursor timeout, forever. And the range query is not bringing me back.
Now I'm really confused. Iteration doesn't work. cursor.skip() doesn't work. Range query doesn't work. And what really works with MongoDB? Or is there something I'm doing really wrong?
Any help would be much appreciated!
Update:
I had some discussion with #AsyaKamsky, he helped me to discover the following things:
setting cursor.batchSize() to 10 doesn't work.
The behaviour is not caused by an idle cursor waiting for 10 minutes. The cursor is pulling data rapidly from server, but still gets invalidated.
The real problem is that after it gets invalid in this way, I could never reallocate any usable cursors anymore. All the new cursors refuse to give me data. There is one possible workaround: close the cursor before this happens, and re-allocate one and use range query to jump back.
Experiments ongoing. Updating this thread in real-time :-)
Update: Failed! I tried renewing cursor after reading 50k records every time. It also gets trapped at this magical index 21800000! That's very close to my cursor.skip() failure offset!
Update:
Confirmed the guessing:
c = db.tweets.find().skip(21800000); //works
c = db.tweets.find().skip(21850000); //doesn't work
I'll try binary search on this range to find the magic number.
Update:
Ok... Magic number found.
db.tweets.find().itcount()
->21837006
db.tweets.find().count()
->253531208
Now what? This is really bad.

Weird JavaScript Code

for (var i=a.length-1;i>0;i--) {
if (i!=a.indexOf(a.charAt(i))) {
a=a.substring(0,i)+a.substring(i+1);
}
}
I found this in a web app I'm auditing, it just baffles me why it's there.
I can't seem to see a case where i!=a.indexOf(a.charAt(i)) would be false.
The value the pass to it is:
a = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
There is no comment either //sigh
This would be true for repeated characters, since indexOf finds the first index of a string, and you're searching from the end. Example:
var a = "xyzxyz";
On first iteration, i === 4, a.charAt(4) === "x", and a.indexOf("x") === 0. So 4 !== 0.
It then sets a = a.substring(0, 4) + a.substring(5). Recalling at substring is inclusive in the first index but exclusive in the last index, that means in this case a = "xyz" + "yz", so we have removed the duplicate "x" from the string.
Since the loop traverses backward, this will continue to work even for characters repeated more than once; you can see that the portion a.substring(i + 1) will always have been covered by the algorithm already, i.e. not contain any duplicates.
As always when encountering this type of thing, applying the extract method refactoring would be a great way to make the code clearer. (Even better than commenting it!) So if you just pulled this out into a method, the code could become a = removeDuplicateChars(a), and everyone is much happier.

Categories

Resources