Find and Break on Repeated Runs

Find and break on repeated runs

Here's a function to do it. By the way, this is a problem in genetics - finding tandem repeats. Here's a link to an algorithm paper that is a much better treatment than this, but much more complicated to implement.

The output is a vector of groups to split x into.

First a helper function:

factorise <- function(x) {
x <- length(x)
if(x == 1){return(1)}
todivide <- seq(from = 2, to = x)
out <- todivide[x %% todivide == 0L]
return(out)
}

Now the main function:

findreps <- function(x, counter = NULL){
if(is.null(counter)){
counter <- c()
maxcounter <- 0
} else {
maxcounter <- max(counter)
}
holding <- lapply(1:length(x), function(y){x[1:y]})
factors <- lapply(holding, factorise)
repeats <- sapply(1:length(factors), function(index) {any(sapply(1:length(factors[[index]]), function(zz) {all((rep(holding[[index]][1:(length(holding[[index]])/factors[[index]][zz])], factors[[index]][zz]))==holding[[index]])}))})
holding <- holding[max(which(repeats))][[1]]
if(length(holding) == length(x)){
return(c(counter, rep(maxcounter + 1, length(x))))
} else {
counter <- c(counter, rep(maxcounter + 1, length(holding)))
return(findreps(x[(length(holding) + 1):length(x)], counter))
}
}

How it works:
It's a recursive function that runs, cuts off the biggest repeats group it can find from the start of the vector, and then runs until they are all gone.

First we make a counter for the final output.

Next, we split x into each subset starting from 1 into a list, holding.

Then we find all factors of the size of a group, except 1.

Then is the worst part. We take each subset of the biggest subset, and check if it is equal to the biggest subset in its group after being repeated the sensible amount of times.

findreps(x)
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3
[37] 3 3 3 3 3 4 5 6 7 7 7 7 7 7 7 7 7

If you want non-repeats to be grouped, we can use a little dplyr and tidyr:

library(dplyr)
library(tidyr)

z <- data.frame(x = x, y = findreps(x))

z %>% mutate(y = ifelse(duplicated(y) | rev(duplicated(rev(y))), y, NA),
holding = c(0, y[2:n()])) %>%
fill(holding) %>%
mutate(y = ifelse(is.na(y), holding +1, y)) %>%
select(-holding)

Which gives:

 [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 7 7 7 7 7 7 7 7
[53] 7

Obtaining the Same Outcome in Repeated Runs - Flipping a Coin

The secret here is to use run length encoding (rle), which will tell you the length of consecutive flips of the same result.

set.seed(1) # Makes example reproducible

coin <- c("heads", "tails")

num_flips <- 10000

flips <- sample(coin, size = num_flips, replace = TRUE)

RLE <- rle(flips)

If we examine the RLE object it will show us the number of consecutive heads and tails:

RLE
#> Run Length Encoding
#> lengths: int [1:4912] 1 1 2 1 3 2 5 4 7 1 ...
#> values : chr [1:4912] "heads" "tails" "heads" "tails" "heads" "tails" "heads" ...

If we table the lengths element, we will get the number of runs of each length:

runs <- table(RLE$lengths)
runs

#> 1 2 3 4 5 6 7 8 9 10 11 12 14 16
#> 2431 1224 581 332 180 84 45 17 10 1 1 2 2 2

If we want to know the proportion of runs that are of each length, we can do:

runs / sum(runs)

#> 1 2 3 4 5 6
#> 0.4949104235 0.2491856678 0.1182817590 0.0675895765 0.0366449511 0.0171009772
#> 7 8 9 10 11 12
#> 0.0091612378 0.0034609121 0.0020358306 0.0002035831 0.0002035831 0.0004071661
#> 14 16
#> 0.0004071661 0.0004071661

However, this is not the same as the estimated probability of any single flip belonging to a run of a particular length. To get this we need to multiply each element of runs by its associated length to get an absolute value for how many flips belong to a run of each length:

results <- runs * as.numeric(names(runs))
results

#> 1 2 3 4 5 6 7 8 9 10 11 12 14 16
#> 2431 2448 1743 1328 900 504 315 136 90 10 11 24 28 32

Now if we want the proportion of flips that belonged to a run of one particular length, we can do:

results / num_flips
#>
#> 1 2 3 4 5 6 7 8 9 10 11
#> 0.2431 0.2448 0.1743 0.1328 0.0900 0.0504 0.0315 0.0136 0.0090 0.0010 0.0011
#> 12 14 16
#> 0.0024 0.0028 0.0032

This is the estimated probability that any single flip will belong to a run of the given length.

Created on 2022-09-26 with reprex v2.0.2

Break from a while loop repeating

The first break statement will never be executed, because the 'if' condition is always false. All of the other break statements break from the switch statement, but not the while loop, so the loop will keep looping forever.
If I understand you correctly, I think you should change the 'false' to 'true' in the first 'if' condition. That being said, the code might overall have a bad design, but you mentioned you are a beginner, so I suggest you also learn how to optimize your code and write efficiently. Good luck.

Can't get my function to run more than once and break my code

while(playerWins === 5 || computerWins === 5)

Your while loop will actually never execute, since you're checking for equality and both playerWins and computerWins are 0 initially.

You may be looking for a condition more like this:

while(playerWins < 5 && computerWins < 5)

Note that we're using the logical AND && instead of the logical OR ||. This is because you don't want to keep looping until both of them win. The logical OR means that even if the computer has won but the player hasn't, we'll continue looping. Only one of the conditions needs to be true for the whole statement to be true.

When we use the logical AND, if one of them is false (meaning, if only one player has reached 5 wins already), then we will break out of the loop as we should.

The next problem is that you have a return statement in your while loop, so after the first execution, even if 5 wins haven't been reached yet, it will return the array of the player's wins and the computer's wins.

You should put the return statement after the loop so that you run the loop 5 times and then return after somebody has won.

And finally, since you haven't provided the rest of the code, I'm not sure if humanVsMachine is actually defined; if you defined that outside of the function then you're good to go.

Is it possible to break a long line to multiple lines in Python?

From PEP 8 - Style Guide for Python Code:

The preferred way of wrapping long lines is by using Python's implied line
continuation inside parentheses, brackets and braces. If necessary, you
can add an extra pair of parentheses around an expression, but sometimes
using a backslash looks better. Make sure to indent the continued line
appropriately.

Example of implicit line continuation:

a = some_function(
'1' + '2' + '3' - '4')

On the topic of line breaks around a binary operator, it goes on to say:

For decades the recommended style was to break after binary operators.
But this can hurt readability in two ways: the operators tend to get scattered across different columns on the screen, and each operator is moved away from its operand and onto the previous line.

In Python code, it is permissible to break before or after a binary operator, as long as the convention is consistent locally. For new code Knuth's style (line breaks before the operator) is suggested.

Example of explicit line continuation:

a = '1'   \
+ '2' \
+ '3' \
- '4'

Python: How to keep repeating a program until a specific input is obtained?

There are two ways to do this. First is like this:

while True:             # Loop continuously
inp = raw_input() # Get the input
if inp == "": # If it is a blank line...
break # ...break the loop

The second is like this:

inp = raw_input()       # Get the input
while inp != "": # Loop until it is a blank line
inp = raw_input() # Get the input again

Note that if you are on Python 3.x, you will need to replace raw_input with input.

Running an allocation simulation repeatedly breaks after the first run

Do you really intend to set the supervisor's quota to 0 in resetData()? Doesn't that mean all their projects are now blocked?

Quoth the raven:

The supervisor has a fixed quota of students he can supervise. This is decremented by 1. Once the quota hits 0, all the projects from that supervisor become blocked and this has the same effect as a project being allocated.

If that's not it, you should check the output of randomiseStudents() to ensure it's returning a full list. It is, after all, the controlling item for that inner loop.


Update based on comments:

It appears the problem was that you were setting the supervisor's quota to 0 thus rendering all their projects blocked.

This is pure guesswork on my part but you probably got one student out in each iteration because the checking of all supervisors happened after an allocation. In that case, the one just allocated would have a quota of -1 and all the other quotas would be 0, effectively stopping all allocations after that one.

Ideally, you'd want to set the supervisor's quota back to their original value in resetData(). If it were a fixed quota (same for each supervisor), you could simply use:

for supervisor in supervisors.itervalues():
supervisor.quota = 7 # for example

If each supervisor had a different quota, you would need to store that along with the other information (during initialisation but not resetting) as, for, example supervisor.start_quota. Then you could use:

for supervisor in supervisors.itervalues():
supervisor.quota = supervisor.start_quota

Python3: How to get repeated response from user and run through the loop once again

First of all, you have a loop that gets age and gives a result, so getting the age should be inside the while loop.

Your age authentication is wrong, let's say you did not enter a proper age (non-digit) and the program asked for another but it would ask to continue to loop afterwards instead of giving a result, this can be solved by using continue instead of getting another age.

Your while loop would continue until end is entered, provided you did not have break and continue, you would have done it your way, but since you do, the better way would be to say the while loop continues forever until exit was entered for the second question.

You do not need the break statements in the if statements that deal with age, if any of them is executed the others would not be checked. Why did you use them?

If you get 'y', the loop would continue automatically so you do not need to explicitly put the continue statement.

You can simplify some of your expressions:

age >= 13 and age <= 90 to 3 <= age <= 12

and

if age.isdigit() != True to if not age.isdigit()

Code

while True:
age = input(prompt)
if age.isdigit() != True:
print("Invalid input, please try again..")
continue
elif age.isdigit() == True:
age = int(age)
if age < 3:
print("Voila, your tickets are free!")
elif age >= 3 and age <= 12:
print("The cost of the ticket is $10")
elif age >= 13 and age <= 90:
print("The cost of the ticket is $15")
else:
print("Sorry, exceeding age limits..")
repeat = input("Do you wanna check more? y/n ")
if repeat != 'y':
break

How can I break out of multiple loops?

My first instinct would be to refactor the nested loop into a function and use return to break out.



Related Topics



Leave a reply



Submit