permutation with local variables bugs - java

I'm testing the permutation codes from Stanford c++ lecture. Why do I introduce a bug if i use my local variables? I tried debugging it but I still don't understand it.
public class JavaApplication9 {
public static void permutate(String so_far, String rest ){
if (rest.equals("")){
System.out.println(so_far);
} else {
for (int i = 0; i < rest.length(); i++){
so_far = so_far + rest.charAt(i);
rest = rest.substring(0,i) + rest.substring(i+1);
permutate(so_far, rest);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
permutate("", "ab");
}
}
Output should be: ab, ba.
Currently getting just: ab

By overwriting the values of rest and so_far inside the for loop, you lose the original version. Here's what the calls to permutate looklike if we unroll the loop.
so_far = "a"
rest = "b"
next time through loop:
so_far = "ab"
rest = ""
Because the values of so_far and rest changed inside the for loop, when i=1, the original values passed in to permutate can't be used only the new modified versions are.
However, if you use different variable names inside your for loop the unrolled loop looks like this:
tmp_so_far = "a"
tmp_rest = "b"
tmp_so_far = "b"
tmp_rest = "a"
Next time through loop:
tmp_so_far = "ab"
tmp_rest = ""
tmp_so_far = "ba"
tmp_rest = ""

Because when you update rest to the new rest, you overwrite the old string. You're modifying it in the loop so when you do rest.length() it's the new length as you've lost the old string.
Example:
when the passed in rest == "ab", in the first iteration rest.length() == 2. but in the loop you updated rest to "b". so when you got back from permute() your rest is now "b" and the length is 1, so when you increment i, it becomes 1 and you fall out of the loop.
Changing to newRest solves the problem as you still have the old rest passed into the method.

Related

Variable in for loop is giving a message that "The value of the local variable i is not used"

I wrote a for loop that is supposed to determine if there is user input. If there is, it sets the 6 elements of int[] valueArr to the input, a vararg int[] statValue. If there is no input, it sets all elements equal to -1.
if (statValue.length == 6) {
for (int i = 0; i < 6; i++) {
valueArr[i] = statValue[i];
}
} else {
for (int i : valueArr) {
i = -1;
}
}
I am using Visual Studio Code, and it is giving me a message in for (int i : valueArr) :
"The value of the local variable i is not used."
That particular for loop syntax is still new to me, so I may be very well blind, but it was working in another file:
for(int i : rollResults) {
sum = sum + i;
}
I feel that I should also mention that the for loop giving me trouble is in a private void method. I'm still fairly new and just recently started using private methods. I noticed the method would give the same message when not used elsewhere, but I do not see why it would appear here.
I tried closing and reopening Visual Studio Code, deleting and retyping the code, and other forms of that. In my short experience, I've had times where I received errors and messages that should not be there and fixed them with what I mentioned, but none of that worked here.
for (int i : valueArr) {
.... CODE HERE ...
}
This sets up a loop which will run CODE HERE a certain number of times. Inside this loop, at the start of every loop, an entirely new variable is created named i, containing one of the values in valueArr. Once the loop ends this variable is destroyed. Notably, i is not directly the value in valueArr - modifying it does nothing - other than affect this one loop if you use i later in within the block. It does not modify the contents of valueArr.
Hence why you get the warning: i = -1 does nothing - you change what i is, and then the loop ends, which means i goes away and your code hasn't changed anything or done anything, which surely you didn't intend. Hence, warning.
It's not entirely clear what you want to do here. If you intend to set all values in valueArr to -1, you want:
for (int i = 0; i < valueArr.length; i++) valueArr[i] = -1;
Or, actually, you can do that more simply:
Arrays.fill(valueArr, -1);
valueArr[i] = -1 changes the value of the i-th value in the valueArr array to -1. for (int i : valueArr) i = -1; does nothing.

How to generate 1000 unique email-ids using java

My requirement is to generate 1000 unique email-ids in Java. I have already generated random Text and using for loop I'm limiting the number of email-ids to be generated. Problem is when I execute 10 email-ids are generated but all are same.
Below is the code and output:
public static void main() {
first fr = new first();
String n = fr.genText()+"#mail.com";
for (int i = 0; i<=9; i++) {
System.out.println(n);
}
}
public String genText() {
String randomText = "abcdefghijklmnopqrstuvwxyz";
int length = 4;
String temp = RandomStringUtils.random(length, randomText);
return temp;
}
and output is:
myqo#mail.com
myqo#mail.com
...
myqo#mail.com
When I execute the same above program I get another set of mail-ids. Example: instead of 'myqo' it will be 'bfta'. But my requirement is to generate different unique ids.
For Example:
myqo#mail.com
bfta#mail.com
kjuy#mail.com
Put your String initialization in the for statement:
for (int i = 0; i<=9; i++) {
String n = fr.genText()+"#mail.com";
System.out.println(n);
}
I would like to rewrite your method a little bit:
public String generateEmail(String domain, int length) {
return RandomStringUtils.random(length, "abcdefghijklmnopqrstuvwxyz") + "#" + domain;
}
And it would be possible to call like:
generateEmail("gmail.com", 4);
As I understood, you want to generate unique 1000 emails, then you would be able to do this in a convenient way by Stream API:
Stream.generate(() -> generateEmail("gmail.com", 4))
.limit(1000)
.collect(Collectors.toSet())
But the problem still exists. I purposely collected a Stream<String> to a Set<String> (which removes duplicates) to find out its size(). As you may see, the size is not always equals 1000
999
1000
997
that means your algorithm returns duplicated values even for such small range.
Therefore, you'd better research already written email generators for Java or improve your own (for example, by adding numbers, some special characters that, in turn, will generate a plenty of exceptions).
If you are planning to use MockNeat, the feature for implementing email strings is already implemented.
Example 1:
String corpEmail = mock.emails().domain("startup.io").val();
// Possible Output: tiptoplunge#startup.io
Example 2:
String domsEmail = mock.emails().domains("abc.com", "corp.org").val();
// Possible Output: funjulius#corp.org
Note: mock is the default "mocking" object.
To guarantee uniqueness you could use a counter as part of the email address:
myqo0000#mail.com
bfta0001#mail.com
kjuy0002#mail.com
If you want to stick to letters only then convert the counter to base 26 representation using 'a' to 'z' as the digits.

All possible distinct subsets of characters in a given string JAVA

As title says I need to do the following. But I somehow am getting the wrong answer, perhaps something with the loops is wrong?
And here's what I have coded so far, but it seems to be giving me the wrong results. Any ideas, help, tips, fixes?
import java.util.ArrayList;
public class pro1
{
private String lettersLeft;
private ArrayList<String> subsets;
public pro1(String input)
{
lettersLeft = input;
subsets = new ArrayList<String>();
}
public void createSubsets()
{
if(lettersLeft.length() == 1)
{
subsets.add(lettersLeft);
}
else
{
String removed = lettersLeft.substring(0,1);
lettersLeft = lettersLeft.substring(1);
createSubsets();
for (int i = 0; i <= lettersLeft.length(); i++)
{
String temp = removed + subsets.get(i);
subsets.add(temp);
}
subsets.add(removed);
}
}
public void showSubsets()
{
System.out.print(subsets);
}
}
My test class is here:
public class pro1
{
public static void main(String[] args)
{
pro1s = new pro1("abba");
s.createSubsets();
s.showSubsets();
}
}
Try
int numSubsets = (int)java.lang.Math.pow(2,toSubset.length());
for (int i=1;i<numSubsets;i++) {
String subset = "";
for (int j=0;j<toSubset.length();j++) {
if ((i&(1<<j))>0) {
subset = subset+toSubset.substring(j,j+1);
}
}
if (!subsets.contains(subset)) {
subsets.add(subset);
}
}
where toSubset is the string that you wish to subset (String toSubset="abba" in your example) and subsets is the ArrayList to contain the results.
To do this we actually iterate over the power set (the set of all subsets), which has size 2^A where A is the size of the original set (in this case the length of your string).
Each subset can be uniquely identified with a number from 0 to 2^A-1 where the value of the jth bit (0 indexed) indicates if that element is present or not with a 1 indicating presence and 0 indicating absence. Note that the number 0 represents the binary string 00...0 which corresponds to the empty set. Thus we start counting at 1 (your example did not show the empty set as a desired subset).
For each value we build a subset string by looking at each bit position and determining if it is a 1 or 0 using bitwise arithmetic. 1<<j is the integer with a 1 in the jth binary place and i&(i<<j) is the integer with 1's only in the places both integers have a 1 (thus is either 0 or 1 based on if i has a 1 in the jth binary digit). If i has a 1 in the jth binary digit, we append the jth element of the string.
Finally, as you asked for unique subsets, we check if we have already used that subset, if not, we add it to the ArrayList.
It is easy to get your head all turned around when working with recursion. Generally, I suspect your problem is that one of the strings you are storing on the way down the recursion rabbit hole for use on the way back up is a class member variable and that your recursive method is a method of that same class. Try making lettersLeft a local variable in the createSubsets() method. Something like:
public class Problem1
{
private String originalInput;
private ArrayList<String> subsets;
public Problem1(String input)
{
originalInput = input;
subsets = new ArrayList<String>();
}
// This is overloading, not recursion.
public void createSubsets()
{
createSubsets(originalInput);
}
public void createSubsets(String in)
{
if(in.length() == 1)
{
// this is the stopping condition, the bottom of the rabbit hole
subsets.add(in);
}
else
{
String removed = in.substring(0,1);
String lettersLeft = in.substring(1);
// this is the recursive call, and you know the input is getting
// smaller and smaller heading toward the stopping condition
createSubsets(lettersLeft);
// this is the "actual work" which doesn't get performed
// until after the above recursive call returns
for (int i = 0; i <= lettersLeft.length(); i++)
{
// possible "index out of bounds" here if subsets is
// smaller than lettersLeft
String temp = removed + subsets.get(i);
subsets.add(temp);
}
subsets.add(removed);
}
}
Something to remember when you are walking through your code trying to think through how it will run... You have structured your recursive method such that the execution pointer goes all the way down the recursion rabbit hole before doing any "real work", just pulling letters off of the input and pushing them onto the stack. All the "real work" is being done coming back out of the rabbit hole while letters are popping off of the stack. Therefore, the first 'a' in your subsets list is actually the last 'a' in your input string 'abba'. I.E. The first letter that is added to your subsets list is because lettersLeft.length() == 1. (in.length() == 1 in my example). Also, the debugger is your friend. Step-debugging is a great way to validate that your code is actually doing what you expect it to be doing at every step along the way.

Why this for statement shows Dead code in Java?

In this class, I defined a constructor that initializes an array and fill it with Point2D.Double. I want to define a toString method that outputs the Point2D.Double in the array. So inside the toString method, I make a for loop that returns every Point2D.Double in the array. The problem is, I don't know why Eclipse tells me that the update in the for statement is dead code.
import java.awt.geom.Point2D;
public class SimplePolygon {
public int n; // number of vertices of the polygon
public Point2D.Double[] vertices; // vertices[0..n-1] around the polygon
// boundary
public SimplePolygon(int size) {
n = size;
vertices = new Point2D.Double[n]; // creates array with n size. Elements are doubles.
for(int i = 0; i < n; i++)
{
Point2D.Double point = new Point2D.Double(Math.random() * 6, Math.random() * 6);
vertices[i] = point;
}
}
public String toString() {
for(int i = 0 ; i < n ; i++)
{
return "" + vertices[i];
}
return "";
}
I too was puzzled by this. (And the other answers!) So I cut-and-pasted it into Eclipse to see what it actually says.
And what Eclipse is actually says is that i++ is unreachable in this line.
for(int i = 0 ; i < n ; i++)
And in fact, that is correct! If you ever enter the loop body, the body will unconditionally return. Hence the i++ can never be executed.
Note also that this is a warning not an error. This code is not invalid according to the JLS rules about unreachability.
You are right to be puzzled by the other explanations. The final return statement is reachable. Consider the case where the class is instantiated with a negative value for n (or size). In that case, the for loop body will never be executed, and control will go to the final return.
However, their suggestions as to how to fix the problem are correct. You should not have a return in the loop body.
The problem is because of the return statement in the for loop. Remember, whenever you use return, you immediately end the method and stop running any code. That means that your toString method will loop exactly only once, returning only vertices[0]. The second return below the loop never has a chance to execute, so is considered dead code.
This is actually incorrect! See Stephan's answer for a better/accurate explanation of what's going on.
Regardless, you still need to fix your code. Instead of returning something inside the loop, you probably want to combine the values and return them all at once at the very end. An easy way to do this might be:
public String toString() {
String output = "";
for(int i = 0 ; i < n ; i++)
{
output += vertices[i] + " ";
}
return output;
}
Now, instead of returning immediately, we're accumulating values in the loop and returning at the very end.
(Note that the code here isn't very efficient -- you'd probably want to use something like String.join or StringBuilder instead, but if you're a beginner, this works for now)

Generating sum of minterms in java

How can I generate the sum of minterms (boolean algebra) in java? We can generate sum of minterms throw ANDing with (X+X'). The following example explains the algorithm for a function with three variables A,B and C:
F(A,B,C)= A + B´*C
= A*(B+B´) + B´*C
= A*B + A*B´ + B´*C
= A*B*(C+C´) + A*B´*(C+C´) + B´*C*(A+A´)
= A*B*C+A*B*C´+A*B´*C+A*B´*C´+B´*C*A+B´*C*A´
= A*B*C+A*B*C´+A*B´*C+A*B´*C´+A*B´*C+A´*B´*C
The method in java looks like this:
String generateSumOfMinterms(String termsOfTheFunction, String variables){}
// Examples for functions with 2 variables A,B
generateSumOfMinterms("A", "A,B"){
//The result should looks like this
return "A*B+A*B'";
}
generateSumOfMinterms("A+B'", "A,B"){
//The result should looks like this (repeated terms are ok for example A*B')
return "A*B+A*B'+A'*B'+A*B'";
}
// Example for a function with 3 variables A,B,C
generateSumOfMinterms("A", "A,B,C"){
//The result should looks like this
return "A*B*C+A*B*C'+A*B'*C+A*B'*C'";
}
I have tried the following:
public List<Minterm> completeMinterm(Minterm minterm, String variables){
List<Minterm> minterms=new ArrayList<Minterm>();
minterms.add(minterm);
Minterm m1=new Minterm();
Minterm m2=new Minterm();
for (int k = 0; k < minterms.size(); k++) {
//A AB--> AB+AB'
for (int i = 0; i < variables.length(); i++) {
boolean varInMinterm=false;
for (int j = 0; j < minterms.get(k).atoms.size(); j++) {
if(minterms.get(k).atoms.get(j).variable==variables.charAt(i)){
varInMinterm=true;
break;
}
}
if(!varInMinterm){
varInMinterm=false;
m1= minterms.get(k);
m1.addAtom(new Atom(variables.charAt(i),false));
m2 = minterms.get(k);
m2.addAtom(new Atom(variables.charAt(i),true));
minterms.remove(k);
minterms.add(m1);
minterms.add(m2);
k=0;
}
}
}
I used eclipse debugger to find errors, I don't understand, why the atom added to m2 is added to m1 too in the same time, when this line is run:
m2.addAtom(new Atom(variables.charAt(i),true));
Here is an outline of a possible approach: First, you should create a more convenient representation of the expression - for example, the expression could be a list of instances of a Minterm class, and Minterm could contain a list of instances of an Atom class, each of which could contain a char that tells which variable it is and a boolean that tells whether the variable is negated or not. The first thing you should do is to loop through termsOfTheFunction and create such objects that represent the expression. Then, you can loop through the minterms, and every time you see a minterm that is missing one variable, you can remove it from the list and add two new minterms with the missing variable. Finally, you can loop through the finished minterms and "print" them to a result String.
Class declarations per request and for clarity (using public fields for brevity):
public class Atom {
public final char variable;
public final bool negated;
public Atom(char variable, bool negated) {
this.variable = variable;
this.negated = negated;
}
}
public class Minterm {
public final List<Atom> atoms = new ArrayList<Atom>();
}
In generateSumOfMinterms():
List<Minterm> expression = new ArrayList<Minterm>();
Minterm currentMinterm = new Minterm();
expression.add(currentMinterm);
Then, loop through the characters of termsOfTheFunction. Each time you see a letter, look at the next character to see if it is a ´, and add an Atom with that letter and with the correct negation. Each time you see a +, create a new Minterm and add it to expression, and keep going. Afterwards, you can start analyzing the minterms and expanding them.
Edit in response to your code: Looks like you're well on your way! The reason both atoms get added to the same minterm is that both m1 and m2 refer to the k'th minterm since you say m1 = minterms.get(k); and m2 = minterms.get(k);. get() does not copy or remove an element from a list; the element will still be inside the list. So for m2, you need to create a new minterm that has all of the atoms from the old one, plus the new atom.

Categories

Resources