switch statement perplexing - switch-statement

I know this has been hashed out before, I've read every question and answer on switch that I can find. My question isn't about syntax or function of Duff's Device but about switch in general this just happens to illustrate the question well.
{
int n = (count + 7) / 8;
switch(count % 8) {
case 0: do { *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
} while(--n > 0);
}
I understand the do while, the value of n is being decremented with each iteration. I also understand that loose compiler rules allow other cases to jump inside the do loop (weird but I understand it)
But since the switch statement is a function of (count % 8) and nothing is changing or acting on the value of count why is count changing in the first place to produce a different modulo remainder inside the switch?
Assume that (count % 8) produces 7 on the first pass. After processing case 7: the value of count remains the same, therefore the value of (count % 8) should remain the same so case 6: should not be true, nor should any other case and without a default n should decrement, and the next iteration of the do loop should begin with the value of count unchanged. So it seems that the loop would wind down to 0, count would never change, so it would only execute case 7 with every pass making all the other code pointless.
But if that were true then Duff's device would not work because it clearly relies on int(n + 7)/8 to produce 8 repetitions of a value of n per value of count and paired with (count % 8) implies that count is indeed decrementing to produce a loop of decreasing modulo remainders between 7 and 0.
From my newbie perspective it would seem for this to work one would need a --count in that loop somewhere. So my conclusion is that I don't understand how switch works. I'd appreciate any explanations.

After doing a little testing with various versions I can safely say that count is not changing value, only n is changing value. Of course that means the original code would work exactly the same without the switch by simply executing the assignment 8 times consecutively inside the do:while which makes me wonder what the point of the switch is to begin with in this case, other than pure obfuscation.
As far as how the switch works, I've discovered through the testing that it works essentially as I expected except that it executes EVERY case regardless of value unless you include a break in each case. Further evidence that count wasn't changing, ergo the lack of breaks in Duff's code coupled with the unchanging value of count further support the assertion that the switch was completely pointless.
This would produce the exact same result;
{
//integer division by 8 produces 8 iterations of the same value
int n = (count + 7) / 8;
do {
*to++ = *from++; //therefore since the loop will be 1/8th
*to++ = *from++;
*to++ = *from++; //the value of count you need to perform
*to++ = *from++;
*to++ = *from++; //8 assignments per iteration of n
*to++ = *from++;
*to++ = *from++; //this produces the same result without
*to++ = *from++;
*to++ = *from++; //the switch
} while(--n > 0);
}

Related

When writing SWITCH statements how can one represent logical operators inside the CASE?

Here's what I've written so far....
case count > 10 & & count %2 == 0:
(document.body.style.backgroundColor = "white").
break;
default:
(document.body.style.backgroundColor = "rgb(186, 155, 111)")
}
}
Tried writing it this way but it's like the code isn't being read at all, I want it to change color if the number is greater than 10 And also an even number...So Thanks!
Also I can't write it in the switch because i am at case 10 already.

Python Logical Operators find the right way if(and and or or)

Can not find the mistake in logical operators, may be someone can give me a hint how to put AND OR OR.
Problem is with if data and data and data and (or or or)
in () > I need to accept code:
contains capital letters, then the number of capitals must be odd
have at least 4 letters (independent of case)
so it means: UPPER + LOWER >= 4 or UPPER >= 4 or LOWER >= 4
output should be:
checker_code("Dfgh#88$")
True
def checker_code(security_code):
data = {'upper':0, 'lower':0, 'spec':0, 'digit':0, 'sum':0}
spec_charact = ['!','#','#','$','%','^','&','*','(',')','?',',','.']
if len(security_code) < 8 or len(security_code) > 30:
return False
for i in security_code:
if any(i.isupper() for i in security_code):
data['upper'] = data['upper'] + 1
if i.islower():
data['lower'] = data['lower'] + 1
if i in spec_charact:
data['spec'] = data['spec'] + 1
if i.isdigit():
data['digit'] = data['digit'] + 1
if i.isdigit():
data['sum'] = data['sum'] + int(i)
if(data['upper'] % 2 !=0 and data['spec'] >= 2 and data['digit'] >= 2 and data['sum'] % 2 == 0 and (data['upper'] + data['lower'] >= 4 or data['upper'] >= 4 or case['lower'] >= 4)):
return True
else:
return False
Change your line
if any(i.isupper() for i in security_code):
to this:
if i.isupper():
Since you are already iterating for i in security_code in your outer for loop, it is redundant to do it again in your first if-statement. I think your code is applying whether the 1st character is upper across all letters, so it thinks your string of 8 characters has 8 upper-case characters since "D" is uppercase
Your test if any(i.isupper() for i in security_code): is adding to data["upper"] everytime through the loop because you are checking all of security_code at every iteration and since it does have a uppercase letter, it adds to the count.
Instead, just do if i.issuper(): to only check the current element of the security code.

Can you combine a while statement and an If statement together into one line?

I am creating a game where it plays to 10 points to win and you can also win if a player reaches 7 points without the other player receiving any.
I have an if statement inside a while statement and was wondering if there was a way to combine them into one general statement.
I have tried combining them with an extra set of parenthesis on for the if portion as well as tried to change up the and/or boolean values to see if I got those wrong.
while (count1 <= 10 and count2 <= 10):
if (count1 == 7 and count2 == 0) or (count2 == 7 and count1 == 0):
Happy Path: The while and if loops combine into one statement, while still keeping the rules stated in the summary.
Currently: I have tried a bunch of combinations but they all go to an else statement or go beyond the 10 point limit, which tells me that the while parameters are wrong.
Try:
while (count1 <= 10 and count2 <= 10) or ((count1 != 7 or count2 != 0) and (count2 != 7 or count1 != 0)):
I'm using following logic laws in here:
not (a or b) <=> not a and not b
and
not (a and b) <=> not a or not b

My current loop which i use to sort elements by their digits produces an list index out of range

Im a complete noob and this is Part of my first sorting algorithm(Radixsort)
So far this way of sorting the numbers by their respective digits is working out but i still get an list index out of range. My theorie is that the while loop takes an extra iteration but i dont understand why.
def put_into_bucket(liste, iteration):
iteration = int
digit = len(liste[0]) - 1
i = 0
while i < len(liste):
if int(liste[i][digit]) == 0:
zero.append(liste[i])
print(zero)
if int(liste[i][digit]) == 1:
one.append(liste[i])
print(one)
if int(liste[i][digit]) == 2:
two.append(liste[i])
print(two)
if int(liste[i][digit]) == 3:
three.append(liste[i])
print(three)
if int(liste[i][digit]) == 4:
four.append(liste[i])
print(four)
if int(liste[i][digit]) == 5:
five.append(liste[i])
print(five)
if int(liste[i][digit]) == 6:
six.append(liste[i])
print(six)
if int(liste[i][digit]) == 7:
seven.append(liste[i])
print(seven)
if int(liste[i][digit]) == 8:
eight.append(liste[i])
print(eight)
if int(liste[i][digit]) == 9:
nine.append(liste[i])
print(nine)
i = i + 1
print(sorted_array)
put_into_bucket(liste=['0001', '0002', '0003', '0004', '0005', '0006'], iteration=0)
As jhnc mentioned, one problem is the bounds check in the while statement. It should be
while i < len(liste)
I still think the increment should be out side the if checks, but you say in the comments that moving it there doubles your output. Since this is not a MCVE, I can't help you with that.
Put the increment outside the if statements. After a successful if check, the next if statement is attempting to use i, which may no longer be valid.
Example
x = 1
if True:
x += 1
if True:
x += 1
print(x)
Output
3
Your other option is to put continue statements at the end of each if block, but you should really move the increment out of the if checks because then you only do it in one place.

In Place Run Length Encoding Algorithm

I encountered an interview question:
Given a input String: aaaaabcddddee, convert it to a5b1c1d4e2.
One extra constraint is, this needs to be done in-place, means no extra space(array) should be used.
It is guaranteed that the encoded string will always fit in the original string. In other words, string like abcde will not occur, since it will be encoded to a1b1c1d1e1 which occupies more space than the original string.
One hint interviewer gave me was to traverse the string once and find the space that is saved.
Still I am stuck as some times, without using extra variables, some values in the input string may be overwritten.
Any suggestions will be appreciated?
This is a good interview question.
Key Points
There are 2 key points:
Single character must be encoded as c1;
The encoded length will always be smaller than the original array.
Since 1, we know each character requires at least 2 places to be encoded. This is to say, only single character will require more spaces to be encoded.
Simple Approach
From the key points, we notice that the single character causes us a lot problem during the encoding, because they might not have enough place to hold the encoded string. So how about we leave them first, and compressed the other characters first?
For example, we encode aaaaabcddddee from the back while leaving the single character first, we will get:
aaaaabcddddee
_____a5bcd4e2
Then we could safely start from the beginning and encoding the partly encoded sequence, given the key point 2 such that there will be enough spaces.
Analysis
Seems like we've got a solution, are we done? No. Consider this string:
aaa3dd11ee4ff666
The problem doesn't limit the range of characters, so we could use digit as well. In this case, if we still use the same approach, we will get this:
aaa3dd11ee4ff666
__a33d212e24f263
Ok, now tell me, how do you distinguish the run-length from those numbers in the original string?
Well, we need to try something else.
Let's define Encode Benefit (E) as: the length difference between the encoded sequence and the original consecutive character sequence..
For example, aa has E = 0, since aa will be encoded to a2, and they have no length difference; aaa has E = 1, since it will be encoded as a3, and the length difference between the encoded and the original is 1. Let's look at the single character case, what's its E? Yes, it's -1. From the definition, we could deduce the formula for E: E = ori_len - encoded_len.
Now let's go back to the problem. From key point 2, we know the encoded string will always be shorter than the original one. How do we use E to rephrase this key point?
Very simple: sigma(E_i) >= 0, where E_i is the Encode Benefit of the ith consecutive character substring.
For example, the sample you gave in your problem: aaaaabcddddee, can be broken down into 5 parts:
E(0) = 5 - 2 = 3 // aaaaa -> a5
E(1) = 1 - 2 = -1 // b -> b1
E(2) = 1 - 2 = -1 // c -> c1
E(3) = 4 - 2 = 2 // dddd -> d4
E(4) = 2 - 2 = 0 // ee -> e2
And the sigma will be: 3 + (-1) + (-1) + 2 + 0 = 3 > 0. This means there will be 3 spaces left after encoding.
However, from this example, we could see a potential problem: since we are doing summing, even if the final answer is bigger than 0, it's possible to get some negatives in the middle!
Yes, this is a problem, and it's quite serious. If we get E falls below 0, this means we do not have enough space to encode the current character and will overwrite some characters after it.
But but but, why do we need to sum it from the first group? Why can't we start summing from somewhere in the middle to skip the negative part? Let's look at an example:
2 0 -1 -1 -1 1 3 -1
If we sum up from the beginning, we will fall below 0 after adding the third -1 at index 4 (0-based); if we sum up from index 5, loop back to index 0 when we reach the end, we have no problem.
Algorithm
The analysis gives us an insight on the algorithm:
Start from the beginning, calculate E of the current consecutive group, and add to the total E_total;
If E_total is still non-negative (>= 0), we are fine and we could safely proceed to the next group;
If the E_total falls below 0, we need to start over from the current position, i.e. clear E_total and proceed to the next position.
If we reach the end of the sequence and E_total is still non-negative, the last starting point is a good start! This step takes O(n) time. Usually we need to loop back and check again, but since key point 2, we will definitely have a valid answer, so we could safely stop here.
Then we could go back to the starting point and start traditional run-length encoding, after we reach the end we need to go back to the beginning of the sequence to finish the first part. The tricky part is, we need to make use the remaining spaces at the end of the string. After that, we need to do some shifting just in case we have some order issues, and remove any extra white spaces, then we are finally done :)
Therefore, we have a solution (the code is just a pseudo and hasn't been verified):
// find the position first
i = j = E_total = pos = 0;
while (i < s.length) {
while (s[i] == s[j]) j ++;
E_total += calculate_encode_benefit(i, j);
if (E_total < 0) {
E_total = 0;
pos = j;
}
i = j;
}
// do run length encoding as usual:
// start from pos, end with len(s) - 1, the first available place is pos
int last_available_pos = runlength(s, pos, len(s)-1, pos);
// a tricky part here is to make use of the remaining spaces from the end!!!
int fin_pos = runlength(s, 0, pos-1, last_available_pos);
// eliminate the white
eliminate(s, fin_pos, pos);
// update last_available_pos because of elimination
last_available_pos -= pos - fin_pos < 0 ? 0 : pos - fin_pos;
// rotate back
rotate(s, last_available_pos);
Complexity
We have 4 parts in the algorithm:
Find the starting place: O(n)
Run-Length-Encoding on the whole string: O(n)
White space elimination: O(n)
In place string rotation: O(n)
Therefore we have O(n) in total.
Visualization
Suppose we need to encode this string: abccdddefggggghhhhh
First step, we need to find the starting position:
Group 1: a -> E_total += -1 -> E_total = -1 < 0 -> E_total = 0, pos = 1;
Group 2: b -> E_total += -1 -> E_total = -1 < 0 -> E_total = 0, pos = 2;
Group 3: cc -> E_total += 0 -> E_total = 0 >= 0 -> proceed;
Group 4: ddd -> E_total += 1 -> E_total = 1 >= 0 -> proceed;
Group 5: e -> E_total += -1 -> E_total = 0 >= 0 -> proceed;
Group 6: f -> E_total += -1 -> E_total = -1 < 0 -> E_total = 0, pos = 9;
Group 7: ggggg -> E_total += 3 -> E_total = 3 >= 0 -> proceed;
Group 8: hhhhh -> E_total += 3 -> E_total = 6 >= 0 -> end;
So the start position will be 9:
v this is the starting point
abccdddefggggghhhhh
abccdddefg5h5______
^ last_available_pos, we need to make use of these remaining spaces
abccdddefg5h5a1b1c2
d3e1f1___g5h5a1b1c2
^^^ remove the white space
d3e1f1g5h5a1b1c2
^ last_available_pos, rotate
a1b1c2d3e1f1g5h5
Last Words
This question is not trivial, and actually glued several traditional coding interview questions together naturally. A suggested mind flow would be:
observe the pattern and figure out the key points;
realize the reason for insufficient space is because of encoding single character;
quantize the benefit/cost of encoding on each consecutive characters group (a.k.a Encoding Benefit);
use the quantization you proposed to explain the original statement;
figure out the algorithm to find a good starting point;
figure out how to do run-length-encoding with a good starting point;
realize you need to rotate the encoded string and eliminate the white spaces;
figure out the algorithm to do in place string rotation;
figure out the algorithm to do in place white space elimination.
To be honest, it's a bit challenging for an interviewee to come up with a solid algorithm in a short time, so your analysis flow really matters. Don't say nothing, show your mind flow, this helps the interviewer to find out your current stage.
Maybe just encode it normally, but if you see that your output index overtakes the input index, just skip the "1". Then when you finish go backwards and insert 1 after all letters without a count, shifting the rest of the string back. It is O(N^2) in the worst case (no repeating letters), so I assume there might be better solutions.
EDIT: it appears I missed the part that the final string always fits into the source. With that restriction, yeah, this is not the optimal solution.
EDIT2: an O(N) version of it would be during the first pass also compute the final compressed length (which in the general case might be more than the source), set pointer p1 to it, a pointer p2 to the compressed string with 1s omitted (p2 is thus <= p1), then just keep going backwards on both pointers, copying p2 to p1 and adding 1s when necessary (when this happens the difference between p2 and p1 will decrease)
O(n) and in place
set var = 0;
Loop from 1-length and find the first non-matching character.
The count would be the difference of the indices of both characters.
Let's run through an example
s = "wwwwaaadexxxxxxywww"
add a dummy letter to s
s = s + '#'
now our string becomes
s = "wwwwaaadexxxxxxywww#"
we'll come back to this step later.
j gives the first character of the string.
j = 0 // s[j] = w
now loop through 1 - length. The first non-matching character is 'a'
print(s[j], i - j) // i = 4, j = 0
j = i // j = 4, s[j] = a
Output: w4
i becomes the next non-matching character which would be 'd'
print(s[j], i - j) // i = 7, j = 4 => a3
j = i // j = 7, s[j] = d
Output: w4a3
.
. (Skipping to the second last)
.
j = 15, s[j] = y, i = 16, s[i] = w
print(s[j], i - y) => y1
Output: w4a3d1e1x6y1
Okay so now we reached the last, assume that we didn't add any dummy letter
j = 16, s[j] = w and we cannot print it's count
because we've no 'mis-matching' character
That's why need to add a dummy letter.
Here's a C++ implementation
void compress(string s){
int j = 0;
s = s + '#';
for(int i=1; i < s.length(); i++){
if(s[i] != s[j]){
cout << s[j] << i - j;
j = i;
}
}
}
int main(){
string s = "wwwwaaadexxxxxxywww";
compress(s);
return 0;
}
Output: w4a3d1e1x6y1w3
If the use of insert and erase string functions are allowed then you can efficiently get the solution with this implementation.
#include<bits/stdc++.h>
using namespace std;
int dig(int n){
int k=0;
while(n){
k++;
n/=10;
}
return k;
}
void stringEncoding(string &n){
int i=0;
for(int i=0;i<n.size();i++){
while(n[i]==n[i+j])j++;
n.erase((i+1),(j-1));
n.insert(i+1,to_string(j));
i+=(dig(j));
}
}
int main(){
ios_base::sync_with_stdio(0), cin.tie(0);
string n="kaaaabcddedddllllllllllllllllllllllp";
stringEncoding(n);
cout<<n;
}
This will give the following output : k1a4b1c1d2e1d3l22p1

Resources