solve equations with unknown variables in it in java - java

I need a function that takes in a equation in the form of a String,
for example: "a * b + 5 * a + 5 + a + 6" and simplifies it in for example:
"a * b + 6 * a +11".
but I can't make my own class work and I can't find a library for it.
I hoped people you could help me

With the Symja library you can solve your problem like in this snippet:
package org.matheclipse.core.examples;
import org.matheclipse.core.eval.ExprEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.parser.client.SyntaxError;
import org.matheclipse.parser.client.math.MathException;
public class SimplifySO55169181 {
public static void main(String[] args) {
try {
ExprEvaluator util = new ExprEvaluator();
IExpr result = util.eval("a * b + 5 * a + 5 + a + 6");
// print: 11+6*a+a*b
System.out.println(result.toString());
} catch (SyntaxError e) {
// catch Symja parser errors here
System.out.println(e.getMessage());
} catch (MathException me) {
// catch Symja math errors here
System.out.println(me.getMessage());
}
}
}

I do not believe there is a standard library for what you ask. However, here are some pointers:
1) Validity check:
Remove all spaces(looping through each character adding it to a String if not space)
Make sure all values are * or + or [letter] or [number]
2) Counting variables:
Create a hashmap who's key is the variable and the value is the sum of the number of letters by looping through the string.
3) Counting variables based on multiplying (such as 6 * a). Loop through, see if variable as follows: [number][variable] or [variable][number]. Add the number - 1 (it was already counted once in step 2.
4) Count constants. Same as 3 except it would be [number]+[number].
5) Print it out in order you see fit.
I changed the pattern slightly. Additionally, for the program to work properly, variables must be lowercase and single characters. Division and subtraction have not been implemented although it would be fairly similar to most of the code. Lastly, the system expesct integers only to function properly.
package com.Bif.MathCondenser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class MathCondenser {
public static void main(String[] args) {
//input equations
String equation = "a * b + 10 * 3 + 50 * a + c * 3 * b * a * 4 * 3";
String equation_temp = "";
//constant character lists
ArrayList<String> alphabet = new ArrayList<String>();
ArrayList<String> numbers = new ArrayList<String>();
ArrayList<String> functions = new ArrayList<String>();
//equation separated into a list of products
ArrayList<String> products = new ArrayList<String>();
//variable definitions of each product
ArrayList<String> definitions = new ArrayList<String>();
ArrayList<String> definitionsDuplicate = new ArrayList<String>();
//collected constants for each product
ArrayList<String> multipliers = new ArrayList<String>();
//reduced terms for the equation
ArrayList<String> terms = new ArrayList<String>();
//fill alphabet arrayList
for(char character = 'a'; character <= 'z'; ++character){
alphabet.add(character-'a', character + "");
}
//fill numbers arrayList
for(int k = 0; k < 10; k++) {
numbers.add("" + k);
}
//fill functions arrayList
functions.add("*");
functions.add("+");
//remove spaces from equation
for(int k = 0; k < equation.length(); k++) {
if(equation.charAt(k) == ' ')
continue;
equation_temp += equation.charAt(k);
}
equation = equation_temp;
System.out.println("Equation: " + equation);
//validate allowed characters; exit if not a-z, 0-9, or *,+
for(int k = 0; k < equation.length(); k++) {
if(!alphabet.contains(equation.charAt(k) + "") && !numbers.contains(equation.charAt(k) + "") && !functions.contains(equation.charAt(k) + "")) {
System.out.println("Valid Characters: false, exiting");
System.exit(0);
}
}
System.out.println("Valid Characters: true, continuing");
//parse the equation into sets of products
Scanner scan = new Scanner(equation);
scan.useDelimiter("\\+");
while(scan.hasNext()) {
products.add(scan.next());
}
System.out.println("Product set:" + products);
//fill definition such that (2 * b * a * 3 * c) -> (abc)
String productAtLocationK;
for(int k = 0; k < products.size(); k++) {
productAtLocationK = products.get(k);
String definition = "";
for(int j = 0; j < productAtLocationK.length(); j++) {
//if it is a letter add it to definition
if(alphabet.contains(productAtLocationK.charAt(j) + "")) {
definition += productAtLocationK.charAt(j);
}
}
//alphabetizes definition
char[] tempDef = definition.toCharArray();
Arrays.sort(tempDef);
definitions.add(new String(tempDef));
definitionsDuplicate.add(new String(tempDef));
}
System.out.println("Definition set: " + definitions);
//fill multiplier set such that (2 * b * a * 3 * c) -> (6)
for(int k = 0; k < products.size(); k++) {
//get the product; default multiplier = 1; character at Location in product;
productAtLocationK = products.get(k);
int multiplier = 1;
String letterInProduct;
//set up scanner for every product in products array with * separator
scan = new Scanner(productAtLocationK);
scan.useDelimiter("\\*");
//loop through product, if (not letter -> number) then update multiplier
while(scan.hasNext()) {
letterInProduct = scan.next();
if(!alphabet.contains(letterInProduct)) {
multiplier *= Integer.parseInt(letterInProduct);
}
}
multipliers.add(multiplier + "");
}
System.out.println("Multiplier set: " + multipliers);
//combine duplicate definitions
int indexOfMultiplier = 0;
while(!definitionsDuplicate.isEmpty()) {
//sum of the constant and its duplicates to combine terms
int constantSum = Integer.parseInt(multipliers.get(indexOfMultiplier++));
String definition = definitionsDuplicate.remove(0);
//check for duplicates, add them to sum
while(definitionsDuplicate.contains(definition)) {
constantSum += Integer.parseInt(multipliers.get(definitionsDuplicate.indexOf(definition)));
definitionsDuplicate.remove(definitionsDuplicate.indexOf(definition));
}
//ignore constant if 1
if(constantSum != 1)
terms.add(constantSum + definition);
else
terms.add(definition);
}
System.out.println("Terms Set: " + terms);
//Format equation
String reducedEquation = "";
for(String term : terms) {
reducedEquation += term + " + ";
}
if(reducedEquation.length() > 1) {
reducedEquation = reducedEquation.substring(0, reducedEquation.length() - 2);
}
System.out.println("Reduced Equation: " + reducedEquation);
//cleanup
scan.close();
}
}

Related

How to separate a String with digits and letters into just digits?

public static String carRentalCode(String licensePlate) {
// precondition: licensePlate is a valid plate as described in pdf
// postcondition: return the car rental code for the licensePlate as described
int values = 0;
int ascii = 0;
int sum = 0;
int convert = 0;
int count = 0;
int a = 0;
char letter;
String license;
char[] ch = new char[licensePlate.length()];
for (int i = 0; i < licensePlate.length(); i++) {
ch[i] = licensePlate.charAt(i);
}
for(int i = 0; i< ch.length; i++)
{
if(Character.isDigit(ch[i]))
{
values += Character.getNumericValue(ch[i]);
}
if(Character.isAlphabetic(ch[i]))
{
ascii += (int) ch[i];
count++;
}
}
sum = values + ascii;
convert = sum%26 + 65;
letter = (char)convert;
String[] letters = licensePlate.split("\\d+");
String lowercase = Arrays.toString(letters).toLowerCase();
String code = Integer.toString(sum);
return letter + code + lowercase;
Here I am supposed to return a car rental code based on a given license plate (the tester plate is "123ABC456"). The only problem I have left is that my lowercase returns as [[,abc]] as opposed to the correct answer which is [abc].
How do you fix the empty space in front, and there being two pairs of brackets instead of one? Or is there any other way to only obtain the letters of a string (ABC), separated from the digits (123 and 456) and return that instead?
Expected: L219[abc]
Actual: L219[[, abc]]
I changed some of your code, use String.toCharArray() to create an array of characters instead of copying it char by char, and replace all your digits by empty string to get only the alphabetic characters
public static String carRentalCode(String licensePlate) {
// precondition: licensePlate is a valid plate as described in pdf
// postcondition: return the car rental code for the licensePlate as described
int values = 0;
int ascii = 0;
int sum = 0;
int convert = 0;
char letter;
char[] ch = licensePlate.toCharArray();
for (int i = 0; i < ch.length; i++) {
if (Character.isDigit(ch[i])) {
values += Character.getNumericValue(ch[i]);
}
if (Character.isAlphabetic(ch[i])) {
ascii += ch[i];
}
}
sum = values + ascii;
convert = sum % 26 + 65;
letter = (char) convert;
String lowercase = licensePlate.replaceAll("\\d+", "").trim().toLowerCase();
String code = Integer.toString(sum);
return letter + code + "[" + lowercase + "]";
}
I just wrote the following code which extracts a word (without a number) from a string:
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Ideone
{
static void extractWord(String str)
{
String regex = "[a-zA-Z]+";
// compiling regex
Pattern p = Pattern.compile(regex);
// Matcher object
Matcher m = p.matcher(str);
while(m.find())
{
System.out.println(m.group());
}
}
public static void main (String[] args)
{
String str = "123ABC456";
extractWord(str);
}
}
Hope this helps you.
Just as an example of a more functional approach:
String lowercase = licensePlate.chars()
.filter(Character::isAlphabetic)
.map(Character::toLowerCase)
.mapToObj(c -> Character.toString((char) c))
.reduce((a, b) -> a + b)
.orElse("");
How about just returning
letter + code + "[" + letters[1].toLowerCase() + "]"

Make parenthesis the first priority on an arithmetic expression on TAC

So I have here my code implementing Three Address Code in arithmetic expression.
class ThreeAddressCode {
private static final char[][] precedence = {
{'/', '1'},
{'*', '1'},
{'+', '2'},
{'-', '2'}
};
private static int precedenceOf(String t)
{
char token = t.charAt(0);
for (int i=0; i < precedence.length; i++)
{
if (token == precedence[i][0])
{
return Integer.parseInt(precedence[i][1]+"");
}
}
return -1;
}
public static void main(String[] args) throws Exception
{
int i, j, opc=0;
char token;
boolean processed[];
String[][] operators = new String[10][2];
String expr="", temp;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.print("\nEnter an expression: ");
expr = in.readLine();
processed = new boolean[expr.length()];
for (i=0; i < processed.length; i++)
{
processed[i] = false;
}
for (i=0; i < expr.length(); i++)
{
token = expr.charAt(i);
for (j=0; j < precedence.length; j++)
{
if (token==precedence[j][0])
{
operators[opc][0] = token+"";
operators[opc][1] = i+"";
opc++;
break;
}
}
}
System.out.println("\nOperators:\nOperator\tLocation");
for (i=0; i < opc; i++)
{
System.out.println(operators[i][0] + "\t\t" + operators[i][1]);
}
//sort
for (i=opc-1; i >= 0; i--)
{
for (j=0; j < i; j++)
{
if (precedenceOf(operators[j][0]) > precedenceOf(operators[j+1][0]))
{
temp = operators[j][0];
operators[j][0] = operators[j+1][0];
operators[j+1][0] = temp;
temp = operators[j][1];
operators[j][1] = operators[j+1][1];
operators[j+1][1] = temp;
}
}
}
System.out.println("\nOperators sorted in their precedence:\nOperator\tLocation");
for (i=0; i < opc; i++)
{
System.out.println(operators[i][0] + "\t\t" + operators[i][1]);
}
System.out.println();
for (i=0; i < opc; i++)
{
j = Integer.parseInt(operators[i][1]+"");
String op1="", op2="";
if (processed[j-1]==true)
{
if (precedenceOf(operators[i-1][0]) == precedenceOf(operators[i][0]))
{
op1 = "t"+i;
}
else
{
for (int x=0; x < opc; x++)
{
if ((j-2) == Integer.parseInt(operators[x][1]))
{
op1 = "t"+(x+1)+"";
}
}
}
}
else
{
op1 = expr.charAt(j-1)+"";
}
if (processed[j+1]==true)
{
for (int x=0; x < opc; x++)
{
if ((j+2) == Integer.parseInt(operators[x][1]))
{
op2 = "t"+(x+1)+"";
}
}
}
else
{
op2 = expr.charAt(j+1)+"";
}
System.out.println("t"+(i+1)+" = "+op1+operators[i][0]+op2);
processed[j] = processed[j-1] = processed[j+1] = true;
}
}
}
Sample Output
Input : a * b / c
t1 = a * b
t2 = t1 / c
What the program does is evaluate the arithmetic expression and shows them step by step by operators.
Can you help me to include parenthesis in the priorities? and achieve an output like this
Sample Output
Input : a * ( b + c )
t1 = b + c
t2 = a * t2
Right now, the parenthesis is treated like an operand.
I did not use any of your code. Sorry.
This was a fun one to think about. I have never considered how you would do something like this. It does not follow all of the best practices to a "T", but the question inspired me to consider how you would do this in a rudimentary way.
You could make much of this code smaller by using more Java Frameworks, but it was enjoyable to strictly try to work this out logically.
This code is missing most validation (i.e. The user inputs an erroneous expression)
It does however check if there are an equal number of open and close parenthesis.
Lastly, I had to wrap things up so I did not extend into expressions with nested parenthesis.
Example a * ( b * ( c / d ) - e ) >> this code does not handle this scenario, and would have to be enhanced to accommodate for this.
Otherwise, it should give a pretty good idea as to one way you could go about building a program to work through parenthesis.
I hope it helps
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MathPriority {
public static void main(String[] args) {
String expression = "a * (b * c) + (d / e)"; //You can work out how you want input to com in
List<String> priorityList = getPriorityList(expression);//Find parenthesis and sets priority.
expression = expression.replace(" ", "").replace("(", "").replace(")", "");//Take out any spaces and parenthesis
for (int i = 0; i < priorityList.size(); i++) {//Replaces the piece in parenthesis with var and outputs var
expression = expression.replace(priorityList.get(i), "t" + (i + 1));
System.out.println("t" + (i + 1) + " = " + priorityList.get(i));
}
System.out.println("t" + (priorityList.size() + 1) + " = " + expression);//pushes final variable set
}
//You can use this to build a List of indexes of a character within a String
public static List<Integer> getAllOccurencesOfChar(List<String> expression, String indexO) {
List<Integer> parIndexList = new ArrayList<>();
for (int i = 0; i < expression.size(); i++) {
if (expression.get(i).contains(indexO)) {
if (!parIndexList.contains(i) && i > 0) {
parIndexList.add(i);
}
}
}
return parIndexList;
}
//Outputs a list of substrings. They can later be used to parse through the inital string
public static List<String> getPriorityList(String expression) {
List<String> priorityList = new ArrayList<>();
expression = expression.replace(" ", "");
String[] eParts = expression.split("");
List<String> expressionParts = new ArrayList<>();//Get expression into single chars
for (String e : eParts) {//If you change this to an Array.List, it will not work. This type of list is fixed in size
expressionParts.add(e);
}
List<Integer> parIndexList = getAllOccurencesOfChar(expressionParts, "(");//find all open paranthesis
List<Integer> rParIndexList = getAllOccurencesOfChar(expressionParts, ")");//find all close paranthesis
if (parIndexList.size() != rParIndexList.size()) {
System.out.println("Your Equation does not have an equal number of open and close parenthesis");
System.exit(0);
}
//Work out the parenthesis
int loopIterator = parIndexList.size();//This will change as we iterate
for (int pars = loopIterator - 1; pars >= 0; pars--) {
int start = parIndexList.get(pars); //Define a start
int end = 0; //and End
//int end = rParIndexList.get(pars);
for (int contemplate = 0; contemplate < loopIterator; contemplate++) {//contemplate where given parenthesis starts and where its closing tag is
if (parIndexList.get(pars) < rParIndexList.get(contemplate)) {
end = rParIndexList.get(contemplate);//find first occurence and set true end
break;//then stop
}
}
String expre = "";
for (int concat = start + 1; concat < end; concat++) {
expre += expressionParts.get(concat);//put the priorityList's subExpression together
}
priorityList.add(expre);//add that subExpression to the list
expressionParts.subList(start, end + 1).clear();//remove these expressionParts
/*Re-establish where the parenthesis are, since we removed parts of the expression in the list*/
parIndexList = getAllOccurencesOfChar(expressionParts, "(");//find all open paranthesis
rParIndexList = getAllOccurencesOfChar(expressionParts, ")");//find all close paranthesis
loopIterator = parIndexList.size();//resize the forLoop
}
return priorityList;
}
public static List<Integer> getStartEndPosition(String fullExpression, String subExpression) {
List<Integer> sAndE = new ArrayList<>();
String[] eParts = subExpression.split("");
List<String> wordParts = new ArrayList<>();
wordParts.addAll(Arrays.asList(eParts));
/*Find multiples of same operand*/
List<Integer> add = getAllOccurencesOfChar(wordParts, "+");
List<Integer> subtract = getAllOccurencesOfChar(wordParts, "-");
List<Integer> divide = getAllOccurencesOfChar(wordParts, "/");
List<Integer> multiply = getAllOccurencesOfChar(wordParts, "*");
/*Find single Operands*/
int plus = subExpression.indexOf("+");
int minus = subExpression.indexOf("-");
int div = subExpression.indexOf("/");
int mult = subExpression.indexOf("*");
int multiOperands = plus + minus + div + mult;//See if multiples exist
int startingPosition = 0;
if (add.size() > 1 || subtract.size() > 1 || divide.size() > 1 || multiply.size() > 1
|| multiOperands > 0) {
//expression has multiple opreands of different types
String findStart = wordParts.get(0) + wordParts.get(1);
String findEnd = wordParts.get(wordParts.size() - 2) + wordParts.get(wordParts.size() - 1);
startingPosition = fullExpression.indexOf(findStart);
sAndE.add(startingPosition);
int endPosition = fullExpression.indexOf(findEnd);
sAndE.add(endPosition);
} else {
startingPosition = fullExpression.indexOf(subExpression);
sAndE.add(startingPosition);
sAndE.add(startingPosition + subExpression.length());
}
return sAndE;
}
}
String expression = "a * (b * c) + (d / e)"
Outputs:
t1 = d/e
t2 = b*c
t3 = a*t2+t1

Print all Digrams and their frequencies in a string

I'm trying to write a program that reads a string of text and prints all digrams in this text and their frequencies. A digram is a sequence of two characters. The program prints digrams sorted based on frequencies (in descending
order).
Example of input: park car at the parking lot
Corresponding output: ar:3 pa:2 rk:2 at:1 ca:1 he:1 in:1 ki:1 lo:1 ng:1 ot:1 th:1
I have this implementation but it only works for every character in the string. How would I implement this for every digram?
import java.util.Scanner;
public class Digrams {
public static void main(String args[]) {
int ci, i, j, k, l=0;
String str, str1;
char c, ch;
Scanner scan = new Scanner(System.in);
System.out.print("Enter a String : ");
str=scan.nextLine();
i=str.length();
for(c='A'; c<='z'; c++)
{
k=0;
for(j=0; j<i; j++)
{
ch = str.charAt(j);
if(ch == c)
{
k++;
}
}
if(k>0)
{
System.out.println("" +c +": " +k);
}
}
}
}
I know you've already got perfect answers and much much better than this, but I was wondering if I can sort the result in descending order without the help of Collections Class, it may be of help, or a new idea.
import java.util.ArrayList;
import java.util.Scanner;
public class Digrams{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
System.out.println("Insert The Sentence");
String []sentence = in.nextLine().split(" "); // split the input according to the spaces and put them in array
//get all digrams
ArrayList<String> allDigrams = new ArrayList<String>(); // ArrayList to contain all possible digrams
for(int i=0; i<sentence.length; i++){ // do that for every word
for(int j=0; j<sentence[i].length(); j++){ // cycle through each char at each index in the sentence array
String oneDigram= "";
if(j<sentence[i].length()-1){
oneDigram += sentence[i].charAt(j); // append the char and the following char
oneDigram += sentence[i].charAt(j+1);
allDigrams.add(oneDigram); // add the one diagram to the ArrayList
}
}
}
// isolate digrams and get corresponding frequencies
ArrayList<Integer> frequency = new ArrayList<Integer>(); // for frequencies
ArrayList<String> digrams = new ArrayList<String>(); //for digrams
int freqIndex=0;
while(allDigrams.size()>0){
frequency.add(freqIndex,0);
for(int j=0; j<allDigrams.size(); j++){ // compare each UNIQUE digram with the rest of the digrams to find repetition
if(allDigrams.get(0).equalsIgnoreCase(allDigrams.get(j))){
frequency.set(freqIndex, frequency.get(freqIndex)+1); // increment frequency
}
}
String dig = allDigrams.get(0); // record the digram temporarily
while(allDigrams.contains(dig)){ // now remove all repetition from the allDigrams ArrayList
allDigrams.remove(dig);
}
digrams.add(dig); // add the UNIQUE digram
freqIndex++; // move to next index for the following digram
}
// sort result in descending order
// compare the frequency , if equal -> the first char of digram, if equal -> the second char of digram
// and move frequencies and digrams at every index in each ArrayList accordingly
for (int i = 0 ; i < frequency.size(); i++){
for (int j = 0 ; j < frequency.size() - i - 1; j++){
if (frequency.get(j) < frequency.get(j+1) ||
((frequency.get(j) == frequency.get(j+1)) && (digrams.get(j).charAt(0) > digrams.get(j+1).charAt(0))) ||
((digrams.get(j).charAt(0) == digrams.get(j+1).charAt(0)) && (digrams.get(j).charAt(1) > digrams.get(j+1).charAt(1)))){
int swap = frequency.get(j);
String swapS = digrams.get(j);
frequency.set(j, frequency.get(j+1));
frequency.set(j+1, swap);
digrams.set(j, digrams.get(j+1));
digrams.set(j+1, swapS);
}
}
}
//final result
String sortedResult="";
for(int i=0; i<frequency.size(); i++){
sortedResult+=digrams.get(i) + ":" + frequency.get(i) + " ";
}
System.out.println(sortedResult);
}
}
Input
park car at the parking lot
Output
ar:3 pa:2 rk:2 at:1 ca:1 he:1 in:1 ki:1 lo:1 ng:1 ot:1 th:1
The way to do it is to check for every 2 letter combination, and look for those instead. You can do this by using a double for-loop, like so:
public static void main(String args[]) {
int ci, i, j, k, l=0;
String str, str1, result, subString;
char c1, c2, ch;
Scanner scan = new Scanner(System.in);
System.out.print("Enter a String : ");
str=scan.nextLine();
i=str.length();
for(c1='A'; c1<='z'; c1++)
{
for(c2='A'; c2<='z'; c2++) {
result = new String(new char[]{c1, c2});
k = 0;
for (j = 0; j < i-1; j++) {
subString = str.substring(j, j+2);
if (result.equals(subString)) {
k++;
}
}
if (k > 0) {
System.out.println("" + result + ": " + k);
}
}
}
}
This also means you have to compare Strings, rather than comparing chars. This of course means the .equals() function needs to be used, rather than the == operator, since String is an object in Java.
Result for me was:
ar: 3 at: 1 ca: 1 he: 1 in: 1 ki: 1 lo: 1 ng: 1 ot: 1 pa: 2 rk: 2 th: 1
Here's how you do it in one line:
Map<String, Long> digramFrequencies = Arrays
.stream(str
.replaceAll("(?<!^| ).(?! |$)", "$0$0") // double letters
.split(" |(?<=\\G..)")) // split into digrams
.filter(s -> s.length() > 1) // discard short terms
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
See live demo.
This works by:
doubling all letters not at start/end of words, eg "abc defg" becomes "abbc deeffg"
splitting into pairs, re-starting splits at start of word
discarding short terms (eg words like "I" and "a")
counting frequencies
This should help:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("Enter a String : ");
String str = scan.nextLine();
ArrayList<String> repetition = new ArrayList<String>();
ArrayList<String> digrams = new ArrayList<String>();
String digram;
for(int i = 0; i < str.length() - 1; i++) {
digram = str.substring(i, i + 2);
if(repetition.contains(digram) || digram.contains(" ") || digram.length() < 2)
continue;
int occurances = (str.length() - str.replace(digram, "").length()) / 2;
occurances += (str.replaceFirst(".*?(" + digram.charAt(0) + "+).*", "$1").length() - 1) / 2;
digrams.add(digram + ":" + occurances);
repetition.add(digram);
}
Collections.sort(digrams, (s1, s2) -> s1.substring(3, 4).compareTo(s2.substring(3, 4)));
System.out.println(digrams);
}
If you don't want to use jdk8 then let me know.

Scrambling strings multiple times in eclipse

I'm having some trouble with some code for a program I'm writing. The purpose of this program is to take a word from a separate text file, scramble it ten times, and display the scrambled letters of the word. The problem that I'm having is that I'm unsure as to how I would go about scrambling the letters ten times. I know that the actual scrambling takes place in my mixer method but the how eludes me. I thought about using a for loop but I'm not sure how to go about it.
import java.io.*;
import java.util.*;
public class Scrambler {
public static void main(String[] args) throws FileNotFoundException {
Scanner input = new Scanner(new File("words.txt"));
String text = input.next();
System.out.println("Original Word: " + text);
System.out.println();
System.out.println("Scrambled Word:");
System.out.println("********");
separate(text);
System.out.println("********");
}
public static void separate(String text) {
System.out
.println(" " + text.charAt(0) + " " + text.charAt(1) + " ");
System.out.println(text.charAt(2) + " " + text.charAt(3));
System.out
.println(" " + text.charAt(4) + " " + text.charAt(5) + " ");
}
public static String mixer(String text) {
Random r = new Random();
int r1 = r.nextInt(text.length());
int r2 = r.nextInt(text.length());
String a = text.substring(0, r1);
char b = text.charAt(r1);
String c = text.substring(r1 + 1, r2);
char d = text.charAt(r2);
String e = text.substring(r2 + 1, text.length());
text = a + b + c + d + e;
return text;
}
}
Your mixer() is not working properly. I would first make the string into an char[], and then retrieve 2 random indices and switch the characters in these indices.
char[] stringasarray = text.toCharArray();
int length = text.length;
for(int i=0; i<length; i++){
int letter1 = rnd.nextInt(length);
int letter2 = rnd.nextInt(length);
char temp = stringasarray[letter1];
stringasarray[letter1] = stringasarray[letter2];
stringasarray[letter2] = temp;
}
String newtext = new String(stringasarray);
A simple for loop would do it:
String word = "Hello World";
for(int i = 0; i < 10; i++){
word = mixer(word);
}
Here is one approach for scrambling the string(s) ten times;
// Passing in the Random.
public static String mixer(String in, Random rnd) {
StringBuilder sb = new StringBuilder();
if (in != null) { // <-- check for null.
List<Character> chars = new ArrayList<Character>();
for (char ch : in.toCharArray()) {
chars.add(ch); // <-- add each character to the List.
}
Collections.shuffle(chars, rnd); // <-- "scramble"
for (char ch : chars) {
sb.append(ch);
}
}
return sb.toString();
}
public static void main(String[] args) {
String t = "Hello";
Random rnd = new Random();
// I'm not sure why you want to do it 10 times, but here is one way.
for (int i =0; i < 10; i++) {
t = mixer(t, rnd); // <-- call mixer function.
}
System.out.println(t);
}
public static String mixer(String text) {
Random r = new Random();
int r1 = r.nextInt(text.length()); // generates a random number from 0 to text.length - 1
int r2 = r.nextInt(text.length()); //generates a random number from 0 to text.length - 1
String a = text.substring(0, r1); // creates a substring containing characters from 0 to r1
char b = text.charAt(r1); //grabs the character at r1
String c = text.substring(r1 + 1, r2); // creates a substring from r1+1 to r2
char d = text.charAt(r2); // grabs the character at r2
String e = text.substring(r2 + 1, text.length()); // grabs any remaining characters
text = a + b + c + d + e; // recombines them
return text;
}
without delving into how substring works, this would most likely return the exact same string. If you changed the order of a + b + c + d + e it would scramble it. It takes the word and divides it into five pieces, then reassembles it.
It could probably use a lot of error checking, however, and some validation.

Find Shortest Part of Sentence containing given words

Ex:
if there is a sentence given:
My name is not eugene. my pet name is not eugene.
And we have to search the smallest part in the sentence that Contains the given words
my and eugene
then the answer will be
eugene. my.
No need to check the uppercase or lowercase or special charaters or numerics.
I have pasted my code but getting wrong answer for some test cases.
can any one have any idea what is the problem with the code . I don't have the test case for which it is wrong.
import java.io.*;
import java.util.*;
public class ShortestSegment
{
static String[] pas;
static String[] words;
static int k,st,en,fst,fen,match,d;
static boolean found=false;
static int[] loc;
static boolean[] matches ;
public static void main(String s[]) throws IOException
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
pas = in.readLine().replaceAll("[^A-Za-z ]", "").split(" ");
k = Integer.parseInt(in.readLine());
words = new String[k];
matches = new boolean[k];
loc = new int[k];
for(int i=0;i<k;i++)
{
words[i] = in.readLine();
}
en = fen = pas.length;
find(0);
if(found==false)
System.out.println("NO SUBSEGMENT FOUND");
else
{
for(int j=fst;j<=fen;j++)
System.out.print(pas[j]+" ");
}
}
private static void find(int min)
{
if(min==pas.length)
return;
for(int i=0;i<k;i++)
{
if(pas[min].equalsIgnoreCase(words[i]))
{
if(matches[i]==false)
{
loc[i]=min;
matches[i] =true;
match++;
}
else
{
loc[i]=min;
}
if(match==k)
{
en=min;
st = min();
found=true;
if((fen-fst)>(en-st))
{
fen=en;
fst=st;
}
match--;
matches[getIdx()]=false;
}
}
}
find(min+1);
}
private static int getIdx()
{
for(int i=0;i<k;i++)
{
if(words[i].equalsIgnoreCase(pas[st]))
return i;
}
return -1;
}
private static int min()
{
int min=loc[0];
for(int i=1;i<loc.length;i++)
if(min>loc[i])
min=loc[i];
return min;
}
}
The code you've given will produce incorrect output for the following input. I'm assuming, the word length also matters when you want to 'Find Shortest Part of Sentence containing given words'
String: 'My firstname is eugene. My fn is eugene.'
Number of search strings: 2
string1: 'my'
string2: 'is'
Your solution is: 'My firstname is'
The correct answer is: 'My fn is'
The problem in your code is, it considers both 'firstname' and 'fn' as same length. In the comparison (fen-fst)>(en-st) you're only considering whether the number of words has minimized and not whether the word lengths has shortened.
the following codes (junit):
#Test
public void testIt() {
final String s = "My name is not eugene. my pet name is not eugene.";
final String tmp = s.toLowerCase().replaceAll("[^a-zA-Z]", " ");//here we need the placeholder (blank)
final String w1 = "my "; // leave a blank at the end to avoid those words e.g. "myself", "myth"..
final String w2 = "eugene ";//same as above
final List<Integer> l1 = getList(tmp, w1); //indexes list
final List<Integer> l2 = getList(tmp, w2);
int min = Integer.MAX_VALUE;
final int[] idx = new int[] { 0, 0 };
//loop to find out the result
for (final int i : l1) {
for (final int j : l2) {
if (Math.abs(j - i) < min) {
final int x = j - i;
min = Math.abs(j - i);
idx[0] = j - i > 0 ? i : j;
idx[1] = j - i > 0 ? j + w2.length() + 2 : i + w1.length() + 2;
}
}
}
System.out.println("indexes: " + Arrays.toString(idx));
System.out.println("result: " + s.substring(idx[0], idx[1]));
}
private List<Integer> getList(final String input, final String search) {
String t = new String(input);
final List<Integer> list = new ArrayList<Integer>();
int tmp = 0;
while (t.length() > 0) {
final int x = t.indexOf(search);
if (x < 0 || x > t.length()) {
break;
}
tmp += x;
list.add(tmp);
t = t.substring(search.length() + x);
}
return list;
}
give output:
indexes: [15, 25]
result: eugene. my
I think the codes with inline comments are pretty easy to understand. basically, playing with index+wordlength.
Note
the "Not Found" case is not implemented.
codes are just showing the
idea, it can be optimized. e.g. at least one abs() could be saved.
etc...
hope it helps.
I think it can be handled in another way :
First , find a matching result , and minimize the bound to the current result and then find a matching result from the current result .It can be coded as follows:
/**This method intends to check the shortest interval between two words
* #param s : the string to be processed at
* #param first : one of the words
* #param second : one of the words
*/
public static void getShortestInterval(String s , String first , String second)
{
String situationOne = first + "(.*?)" + second;
String situationTwo = second + "(.*?)" + first;
Pattern patternOne = Pattern.compile(situationOne,Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
Pattern patternTwo = Pattern.compile(situationTwo,Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
List<Integer> result = new ArrayList<Integer>(Arrays.asList(Integer.MAX_VALUE,-1,-1));
/**first , test the first choice*/
Matcher matcherOne = patternOne.matcher(s);
findTheMax(first.length(),matcherOne, result);
/**then , test the second choice*/
Matcher matcherTwo = patternTwo.matcher(s);
findTheMax(second.length(),matcherTwo,result);
if(result.get(0)!=Integer.MAX_VALUE)
{
System.out.println("The shortest length is " + result.get(0));
System.out.println("Which start # " + result.get(1));
System.out.println("And end # " + result.get(2));
}else
System.out.println("No matching result is found!");
}
private static void findTheMax(int headLength , Matcher matcher , List<Integer> result)
{
int length = result.get(0);
int startIndex = result.get(1);
int endIndex = result.get(2);
while(matcher.find())
{
int temp = matcher.group(1).length();
int start = matcher.start();
List<Integer> minimize = new ArrayList<Integer>(Arrays.asList(Integer.MAX_VALUE,-1,-1));
System.out.println(matcher.group().substring(headLength));
findTheMax(headLength, matcher.pattern().matcher(matcher.group().substring(headLength)), minimize);
if(minimize.get(0) != Integer.MAX_VALUE)
{
start = start + minimize.get(1) + headLength;
temp = minimize.get(0);
}
if(temp<length)
{
length = temp;
startIndex = start;
endIndex = matcher.end();
}
}
result.set(0, length);
result.set(1, startIndex);
result.set(2, endIndex);
}
Note that this can handle two situations , regardless of the sequence of the two words!
you can use Knuth Morris Pratt algorithm to find indexes of all occurrences of every given word in your text. Imagine you have text of length N and M words (w1 ... wM). Using KMP algorithm you can get array:
occur = string[N];
occur[i] = 1, if w1 starts at position i
...
occur[i] = M, if wM starts at position i
occur[i] = 0, if no word from w1...wM starts at position i
you loop through this array and from every non-zero position search forward for other M-1 words.
This is approximate pseudocode. Just to understand the idea. It definitely won't work if you just recode it on java:
for i=0 to N-1 {
if occur[i] != 0 {
for j = i + w[occur[i] - 1].length - 1 { // searching forward
if occur[j] != 0 and !foundWords.contains(occur[j]) {
foundWords.add(occur[j]);
lastWordInd = j;
if foundWords.containAllWords() break;
}
foundTextPeaceLen = j + w[occur[lastWordInd]].length - i;
if foundTextPeaceLen < minTextPeaceLen {
minTextPeaceLen = foundTextPeaceLen;
// also remember start and end indexes of text peace
}
}
}
}

Categories

Resources