Compare RDD Objects - Apache Spark - java

I'm fairly new into the apache spark technology and I'm having some problems while trying to analyze data I'm pulling from my files.
I have big list of genes information, and I'm pulling that information to a RDD, so far so good.
JavaRDD<Gene> inputfile = sc.textFile(logFile).map(
new Function<String, Gene>() {
#Override
public Gene call(String line) throws Exception {
String[] values = line.split("\t");
Gene gen = null;
//We are only interested in genes;
if( values.length > 2 && values[2].equalsIgnoreCase("gene") && !line.contains("#")){
String[] infoGene = values[8].split(";");
String geneId = StringUtils.substringBetween(infoGene[0], "\"");
String geneType = StringUtils.substringBetween(infoGene[2], "\"");
String geneName = StringUtils.substringBetween(infoGene[4], "\"");
gen = new Gene(geneName,values[3],values[4]);
return gen;
}
return gen;
}
}
).filter(new Function<Gene, Boolean>() {
#Override
public Boolean call(Gene gene) throws Exception {
if(gene == null)
return false;
else
return true;
}
});
The Gene class:
public class Gene implements Serializable{
String firstBp;
String lastBp;
String name;
public Gene(String name, String firstBp, String lastBp) {
this.name = name;
this.firstBp = firstBp;
this.lastBp = lastBp;
}
public String getFirstBp() {
return firstBp;
}
public String getLastBp() {
return lastBp;
}
public String getName() {
return name;
}
public String toString(){
return name + " " + firstBp + " " + lastBp;
}}
The problem starts here, I need to analyze if 2 Genes overlay, and for that I've made this simple utility function:
public static Boolean isOverlay(Gene gene1, Gene gene2){
int gene1First = Integer.parseInt(gene1.getFirstBp());
int gene1Last = Integer.parseInt(gene1.getLastBp());
int gene2First = Integer.parseInt(gene2.getFirstBp());
int gene2Last = Integer.parseInt(gene2.getLastBp());
if(gene2First >= gene1First && gene2First <= gene1Last) // FirstBp - Gene2 inside
return true;
else if (gene2Last >= gene1First && gene2Last <= gene1Last) // LastBP - Gene2 inside
return true;
else if (gene1First >= gene2First && gene1First <= gene2Last) // FirstBp - Gene1 inside
return true;
else if (gene1Last >= gene2First && gene1Last <= gene2Last) // LastBP - Gene1 inside
return true;
else
return false;
}
Now what I'm doing and I think is wrong is transforming the RDD Object into a list by doing:
List<Gene> genesList = inputfile.collect();
And iterate over that list to check if there are overlays and save to the file the results which is taking ages because I'm not using spark.
List<OverlayPair> overlayPairList= new ArrayList<OverlayPair>();
List<String> visitedGenes = new ArrayList<String>();
for (Gene gene1 : genesList){
for (Gene gene2 : genesList) {
if (gene1.getName().equalsIgnoreCase(gene2.getName()) || visitedGenes.contains(gene2.getName())) {
continue;
}
if (isOverlay(gene1, gene2))
overlayPairList.add(new OverlayPair(gene1.getName(), gene2.getName()));
}
visitedGenes.add(gene1.getName());
}
JavaRDD<OverlayPair> overlayFile = sc.parallelize(overlayPairList);
//Export the results to the file
String outputDirectory = "/Users/joaoalmeida/Desktop/Dissertacao/sol/data/mitocondrias/feup-pp/project/data/output/overlays";
overlayFile.coalesce(1).saveAsTextFile(outputDirectory);
The Overlay pair is basically an object with the 2 genes name.
Is there anyway to do this 2nd part while taking advantage of spark? Because the time complexity of those 2 for's its to big for the amount of data I currently have.

Yes, there is, you have to use RDD.cartesian function to get all the pairs and then you can basically apply the function you wrote.

Related

How to convert string in a txt document to code? [duplicate]

I have a string like the following:
String str = "4*5";
Now I have to get the result of 20 by using the string.
I know in some other languages the eval() function will do this.
How can I do this in Java?
You can use the ScriptEngine class and evaluate it as a Javascript string.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Object result = engine.eval("4*5");
There may be a better way, but this one works.
There is no standard Java class or method that will do what you want. Your options include:
Select and use some third-party expression evaluation library. For example JEL or any of the half dozen libraries listed here.
Wrap the expression in the Java source code for a class with an eval method, send that to the Java compiler, and then load the resulting compiled class.
Use some scripting language that can be called from Java as an expression evaluator. Possibilities include Javascript1, BeanShell, and so on. A JSR 223 compliant scripting language implementation can be called via the Scripting API.
Write your own expression evaluator from scratch.
The first approach is probably simplest. The second and third approaches are a potential security risk if you get the expression to be evaluated from an untrusted user. (Think code injection.)
1 - Javascript in Java SE is a moving target. From Java 6, a version of Mozilla's Rhino Javascript implementation was bundled with Java SE. The in Java 8, it was superseded by Nashorn. In Java 11, Nashorn was deprecated, and finally dropped from the core codebase. As of 2021, both Rhino and Nashorn are being maintained as separate (non-Oracle) products, and Oracle's GraalVM has its own Javascript implementation.
There are very few real use cases in which being able to evaluate a String as a fragment of Java code is necessary or desirable. That is, asking how to do this is really an XY problem: you actually have a different problem, which can be solved a different way.
First ask yourself, where did this String that you wish to evaluate come from? Did another part of your program generate it, or was it input provided by the user?
Another part of my program generated it: so, you want one part of your program to decide the kind of operation to perform, but not perform the operation, and a second part that performs the chosen operation. Instead of generating and then evaluating a String, use the Strategy, Command or Builder design pattern, as appropriate for your particular case.
It is user input: the user could input anything, including commands that, when executed, could cause your program to misbehave, crash, expose information that should be secret, damage persistent information (such as the content of a database), and other such nastiness. The only way to prevent that would be to parse the String yourself, check it was not malicious, and then evaluate it. But parsing it yourself is much of the work that the requested evalfunction would do, so you have saved yourself nothing. Worse still, checking that arbitrary Java was not malicious is impossible, because checking that is the halting problem.
It is user input, but the syntax and semantics of permitted text to evaluate is greatly restricted: No general purpose facility can easily implement a general purpose parser and evaluator for whatever restricted syntax and semantics you have chosen. What you need to do is implement a parser and evaluator for your chosen syntax and semantics. If the task is simple, you could write a simple recursive-descent or finite-state-machine parser by hand. If the task is difficult, you could use a compiler-compiler (such as ANTLR) to do some of the work for you.
I just want to implement a desktop calculator!: A homework assignment, eh? If you could implement the evaluation of the input expression using a provided eval function, it would not be much of a homework assignment, would it? Your program would be three lines long. Your instructor probably expects you to write the code for a simple arithmetic parser/evaluator. There is well known algorithm, shunting-yard, which you might find useful.
With Java 9, we get access to jshell, so one can write something like this:
import jdk.jshell.JShell;
import java.lang.StringBuilder;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Eval {
public static void main(String[] args) throws IOException {
try(JShell js = JShell.create(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
js.onSnippetEvent(snip -> {
if (snip.status() == jdk.jshell.Snippet.Status.VALID) {
System.out.println("➜ " + snip.value());
}
});
System.out.print("> ");
for (String line = br.readLine(); line != null; line = br.readLine()) {
js.eval(js.sourceCodeAnalysis().analyzeCompletion(line).source());
System.out.print("> ");
}
}
}
}
Sample run:
> 1 + 2 / 4 * 3
➜ 1
> 32 * 121
➜ 3872
> 4 * 5
➜ 20
> 121 * 51
➜ 6171
>
Slightly op, but that's what Java currently has to offer
I could advise you to use Exp4j. It is easy to understand as you can see from the following example code:
Expression e = new ExpressionBuilder("3 * sin(y) - 2 / (x - 2)")
.variables("x", "y")
.build()
.setVariable("x", 2.3)
.setVariable("y", 3.14);
double result = e.evaluate();
No, you can not have a generic "eval" in Java (or any compiled language). Unless you're willing to write a Java compiler AND a JVM to be executed inside of your Java program.
Yes, you can have some library to evaluate numeric algebraic expressions like the one above - see this thread for discussion.
As previous answers, there is no standard API in Java for this.
You can add groovy jar files to your path and groovy.util.Eval.me("4*5") gets your job done.
A fun way to solve your problem could be coding an eval() function on your own!
I've done it for you!
You can use FunctionSolver library simply by typing FunctionSolver.solveByX(function,value) inside your code. The function attribute is a String which represents the function you want to solve, the value attribute is the value of the independent variable
of your function (which MUST be x).
If you want to solve a function which contains more than one independent variable, you can use FunctionSolver.solve(function,values) where the values attribute is an HashMap(String,Double) which contains all your independent attributes (as Strings) and their respective values (as Doubles).
Another piece of information: I've coded a simple version of FunctionSolver, so its supports only Math methods which return a double value and which accepts one or two double values as fields (just use FunctionSolver.usableMathMethods() if you're curious) (These methods are: bs, sin, cos, tan, atan2, sqrt, log, log10, pow, exp, min, max, copySign, signum, IEEEremainder, acos, asin, atan, cbrt, ceil, cosh, expm1, floor, hypot, log1p, nextAfter, nextDown, nextUp, random, rint, sinh, tanh, toDegrees, toRadians, ulp). Also, that library supports the following operators: * / + - ^ (even if java normally does not support the ^ operator).
One last thing: while creating this library I had to use reflections to call Math methods. I think it's really cool, just have a look at this if you are interested in!
That's all, here it is the code (and the library):
package core;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public abstract class FunctionSolver {
public static double solveNumericExpression (String expression) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return solve(expression, new HashMap<>());
}
public static double solveByX (String function, double value) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
HashMap<String, Double> values = new HashMap<>();
values.put("x", value);
return solveComplexFunction(function, function, values);
}
public static double solve (String function, HashMap<String,Double> values) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return solveComplexFunction(function, function, values);
}
private static double solveComplexFunction (String function, String motherFunction, HashMap<String, Double> values) throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
int position = 0;
while(position < function.length()) {
if (alphabetic.contains(""+function.charAt(position))) {
if (position == 0 || !alphabetic.contains(""+function.charAt(position-1))) {
int endIndex = -1;
for (int j = position ; j < function.length()-1 ; j++) {
if (alphabetic.contains(""+function.charAt(j))
&& !alphabetic.contains(""+function.charAt(j+1))) {
endIndex = j;
break;
}
}
if (endIndex == -1 & alphabetic.contains(""+function.charAt(function.length()-1))) {
endIndex = function.length()-1;
}
if (endIndex != -1) {
String alphabeticElement = function.substring(position, endIndex+1);
if (Arrays.asList(usableMathMethods()).contains(alphabeticElement)) {
//Start analyzing a Math function
int closeParenthesisIndex = -1;
int openedParenthesisquantity = 0;
int commaIndex = -1;
for (int j = endIndex+1 ; j < function.length() ; j++) {
if (function.substring(j,j+1).equals("(")) {
openedParenthesisquantity++;
}else if (function.substring(j,j+1).equals(")")) {
openedParenthesisquantity--;
if (openedParenthesisquantity == 0) {
closeParenthesisIndex = j;
break;
}
}else if (function.substring(j,j+1).equals(",") & openedParenthesisquantity == 0) {
if (commaIndex == -1) {
commaIndex = j;
}else{
throw new IllegalArgumentException("The argument of math function (which is "+alphabeticElement+") has too many commas");
}
}
}
if (closeParenthesisIndex == -1) {
throw new IllegalArgumentException("The argument of a Math function (which is "+alphabeticElement+") hasn't got the closing bracket )");
}
String functionArgument = function.substring(endIndex+2,closeParenthesisIndex);
if (commaIndex != -1) {
double firstParameter = solveComplexFunction(functionArgument.substring(0,commaIndex),motherFunction,values);
double secondParameter = solveComplexFunction(functionArgument.substring(commaIndex+1),motherFunction,values);
Method mathMethod = Math.class.getDeclaredMethod(alphabeticElement, new Class<?>[] {double.class, double.class});
mathMethod.setAccessible(true);
String newKey = getNewKey(values);
values.put(newKey, (Double) mathMethod.invoke(null, firstParameter, secondParameter));
function = function.substring(0, position)+newKey
+((closeParenthesisIndex == function.length()-1)?(""):(function.substring(closeParenthesisIndex+1)));
}else {
double firstParameter = solveComplexFunction(functionArgument, motherFunction, values);
Method mathMethod = Math.class.getDeclaredMethod(alphabeticElement, new Class<?>[] {double.class});
mathMethod.setAccessible(true);
String newKey = getNewKey(values);
values.put(newKey, (Double) mathMethod.invoke(null, firstParameter));
function = function.substring(0, position)+newKey
+((closeParenthesisIndex == function.length()-1)?(""):(function.substring(closeParenthesisIndex+1)));
}
}else if (!values.containsKey(alphabeticElement)) {
throw new IllegalArgumentException("Found a group of letters ("+alphabeticElement+") which is neither a variable nor a Math function: ");
}
}
}
}
position++;
}
return solveBracketsFunction(function,motherFunction,values);
}
private static double solveBracketsFunction (String function,String motherFunction,HashMap<String, Double> values) throws IllegalArgumentException{
function = function.replace(" ", "");
String openingBrackets = "([{";
String closingBrackets = ")]}";
int parenthesisIndex = 0;
do {
int position = 0;
int openParenthesisBlockIndex = -1;
String currentOpeningBracket = openingBrackets.charAt(parenthesisIndex)+"";
String currentClosingBracket = closingBrackets.charAt(parenthesisIndex)+"";
if (contOccouranceIn(currentOpeningBracket,function) != contOccouranceIn(currentClosingBracket,function)) {
throw new IllegalArgumentException("Error: brackets are misused in the function "+function);
}
while (position < function.length()) {
if (function.substring(position,position+1).equals(currentOpeningBracket)) {
if (position != 0 && !operators.contains(function.substring(position-1,position))) {
throw new IllegalArgumentException("Error in function: there must be an operator following a "+currentClosingBracket+" breacket");
}
openParenthesisBlockIndex = position;
}else if (function.substring(position,position+1).equals(currentClosingBracket)) {
if (position != function.length()-1 && !operators.contains(function.substring(position+1,position+2))) {
throw new IllegalArgumentException("Error in function: there must be an operator before a "+currentClosingBracket+" breacket");
}
String newKey = getNewKey(values);
values.put(newKey, solveBracketsFunction(function.substring(openParenthesisBlockIndex+1,position),motherFunction, values));
function = function.substring(0,openParenthesisBlockIndex)+newKey
+((position == function.length()-1)?(""):(function.substring(position+1)));
position = -1;
}
position++;
}
parenthesisIndex++;
}while (parenthesisIndex < openingBrackets.length());
return solveBasicFunction(function,motherFunction, values);
}
private static double solveBasicFunction (String function, String motherFunction, HashMap<String, Double> values) throws IllegalArgumentException{
if (!firstContainsOnlySecond(function, alphanumeric+operators)) {
throw new IllegalArgumentException("The function "+function+" is not a basic function");
}
if (function.contains("**") |
function.contains("//") |
function.contains("--") |
function.contains("+*") |
function.contains("+/") |
function.contains("-*") |
function.contains("-/")) {
/*
* ( -+ , +- , *- , *+ , /- , /+ )> Those values are admitted
*/
throw new IllegalArgumentException("Operators are misused in the function");
}
function = function.replace(" ", "");
int position;
int operatorIndex = 0;
String currentOperator;
do {
currentOperator = operators.substring(operatorIndex,operatorIndex+1);
if (currentOperator.equals("*")) {
currentOperator+="/";
operatorIndex++;
}else if (currentOperator.equals("+")) {
currentOperator+="-";
operatorIndex++;
}
operatorIndex++;
position = 0;
while (position < function.length()) {
if ((position == 0 && !(""+function.charAt(position)).equals("-") && !(""+function.charAt(position)).equals("+") && operators.contains(""+function.charAt(position))) ||
(position == function.length()-1 && operators.contains(""+function.charAt(position)))){
throw new IllegalArgumentException("Operators are misused in the function");
}
if (currentOperator.contains(function.substring(position, position+1)) & position != 0) {
int firstTermBeginIndex = position;
while (firstTermBeginIndex > 0) {
if ((alphanumeric.contains(""+function.charAt(firstTermBeginIndex))) & (operators.contains(""+function.charAt(firstTermBeginIndex-1)))){
break;
}
firstTermBeginIndex--;
}
if (firstTermBeginIndex != 0 && (function.charAt(firstTermBeginIndex-1) == '-' | function.charAt(firstTermBeginIndex-1) == '+')) {
if (firstTermBeginIndex == 1) {
firstTermBeginIndex--;
}else if (operators.contains(""+(function.charAt(firstTermBeginIndex-2)))){
firstTermBeginIndex--;
}
}
String firstTerm = function.substring(firstTermBeginIndex,position);
int secondTermLastIndex = position;
while (secondTermLastIndex < function.length()-1) {
if ((alphanumeric.contains(""+function.charAt(secondTermLastIndex))) & (operators.contains(""+function.charAt(secondTermLastIndex+1)))) {
break;
}
secondTermLastIndex++;
}
String secondTerm = function.substring(position+1,secondTermLastIndex+1);
double result;
switch (function.substring(position,position+1)) {
case "*": result = solveSingleValue(firstTerm,values)*solveSingleValue(secondTerm,values); break;
case "/": result = solveSingleValue(firstTerm,values)/solveSingleValue(secondTerm,values); break;
case "+": result = solveSingleValue(firstTerm,values)+solveSingleValue(secondTerm,values); break;
case "-": result = solveSingleValue(firstTerm,values)-solveSingleValue(secondTerm,values); break;
case "^": result = Math.pow(solveSingleValue(firstTerm,values),solveSingleValue(secondTerm,values)); break;
default: throw new IllegalArgumentException("Unknown operator: "+currentOperator);
}
String newAttribute = getNewKey(values);
values.put(newAttribute, result);
function = function.substring(0,firstTermBeginIndex)+newAttribute+function.substring(secondTermLastIndex+1,function.length());
deleteValueIfPossible(firstTerm, values, motherFunction);
deleteValueIfPossible(secondTerm, values, motherFunction);
position = -1;
}
position++;
}
}while (operatorIndex < operators.length());
return solveSingleValue(function, values);
}
private static double solveSingleValue (String singleValue, HashMap<String, Double> values) throws IllegalArgumentException{
if (isDouble(singleValue)) {
return Double.parseDouble(singleValue);
}else if (firstContainsOnlySecond(singleValue, alphabetic)){
return getValueFromVariable(singleValue, values);
}else if (firstContainsOnlySecond(singleValue, alphanumeric+"-+")) {
String[] composition = splitByLettersAndNumbers(singleValue);
if (composition.length != 2) {
throw new IllegalArgumentException("Wrong expression: "+singleValue);
}else {
if (composition[0].equals("-")) {
composition[0] = "-1";
}else if (composition[1].equals("-")) {
composition[1] = "-1";
}else if (composition[0].equals("+")) {
composition[0] = "+1";
}else if (composition[1].equals("+")) {
composition[1] = "+1";
}
if (isDouble(composition[0])) {
return Double.parseDouble(composition[0])*getValueFromVariable(composition[1], values);
}else if (isDouble(composition[1])){
return Double.parseDouble(composition[1])*getValueFromVariable(composition[0], values);
}else {
throw new IllegalArgumentException("Wrong expression: "+singleValue);
}
}
}else {
throw new IllegalArgumentException("Wrong expression: "+singleValue);
}
}
private static double getValueFromVariable (String variable, HashMap<String, Double> values) throws IllegalArgumentException{
Double val = values.get(variable);
if (val == null) {
throw new IllegalArgumentException("Unknown variable: "+variable);
}else {
return val;
}
}
/*
* FunctionSolver help tools:
*
*/
private static final String alphabetic = "abcdefghilmnopqrstuvzwykxy";
private static final String numeric = "0123456789.";
private static final String alphanumeric = alphabetic+numeric;
private static final String operators = "^*/+-"; //--> Operators order in important!
private static boolean firstContainsOnlySecond(String firstString, String secondString) {
for (int j = 0 ; j < firstString.length() ; j++) {
if (!secondString.contains(firstString.substring(j, j+1))) {
return false;
}
}
return true;
}
private static String getNewKey (HashMap<String, Double> hashMap) {
String alpha = "abcdefghilmnopqrstuvzyjkx";
for (int j = 0 ; j < alpha.length() ; j++) {
String k = alpha.substring(j,j+1);
if (!hashMap.containsKey(k) & !Arrays.asList(usableMathMethods()).contains(k)) {
return k;
}
}
for (int j = 0 ; j < alpha.length() ; j++) {
for (int i = 0 ; i < alpha.length() ; i++) {
String k = alpha.substring(j,j+1)+alpha.substring(i,i+1);
if (!hashMap.containsKey(k) & !Arrays.asList(usableMathMethods()).contains(k)) {
return k;
}
}
}
throw new NullPointerException();
}
public static String[] usableMathMethods () {
/*
* Only methods that:
* return a double type
* present one or two parameters (which are double type)
*/
Method[] mathMethods = Math.class.getDeclaredMethods();
ArrayList<String> usableMethodsNames = new ArrayList<>();
for (Method method : mathMethods) {
boolean usable = true;
int argumentsCounter = 0;
Class<?>[] methodParametersTypes = method.getParameterTypes();
for (Class<?> parameter : methodParametersTypes) {
if (!parameter.getSimpleName().equalsIgnoreCase("double")) {
usable = false;
break;
}else {
argumentsCounter++;
}
}
if (!method.getReturnType().getSimpleName().toLowerCase().equals("double")) {
usable = false;
}
if (usable & argumentsCounter<=2) {
usableMethodsNames.add(method.getName());
}
}
return usableMethodsNames.toArray(new String[usableMethodsNames.size()]);
}
private static boolean isDouble (String number) {
try {
Double.parseDouble(number);
return true;
}catch (Exception ex) {
return false;
}
}
private static String[] splitByLettersAndNumbers (String val) {
if (!firstContainsOnlySecond(val, alphanumeric+"+-")) {
throw new IllegalArgumentException("Wrong passed value: <<"+val+">>");
}
ArrayList<String> response = new ArrayList<>();
String searchingFor;
int lastIndex = 0;
if (firstContainsOnlySecond(""+val.charAt(0), numeric+"+-")) {
searchingFor = alphabetic;
}else {
searchingFor = numeric+"+-";
}
for (int j = 0 ; j < val.length() ; j++) {
if (searchingFor.contains(val.charAt(j)+"")) {
response.add(val.substring(lastIndex, j));
lastIndex = j;
if (searchingFor.equals(numeric+"+-")) {
searchingFor = alphabetic;
}else {
searchingFor = numeric+"+-";
}
}
}
response.add(val.substring(lastIndex,val.length()));
return response.toArray(new String[response.size()]);
}
private static void deleteValueIfPossible (String val, HashMap<String, Double> values, String function) {
if (values.get(val) != null & function != null) {
if (!function.contains(val)) {
values.remove(val);
}
}
}
private static int contOccouranceIn (String howManyOfThatString, String inThatString) {
return inThatString.length() - inThatString.replace(howManyOfThatString, "").length();
}
}
Writing your own library is not that hard as u might thing. Here is link for Shunting-yard algorithm with step by step algorithm explenation. Although, you will have to parse the input for tokens first.
There are 2 other questions wich can give you some information too:
Turn a String into a Math Expression?
What's a good library for parsing mathematical expressions in java?
As there are many answers, I'm adding my implementation on top of eval() method with some additional features like support for factorial, evaluating complex expressions etc.
package evaluation;
import java.math.BigInteger;
import java.util.EmptyStackException;
import java.util.Scanner;
import java.util.Stack;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class EvalPlus {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("This Evaluation is based on BODMAS rule\n");
evaluate();
}
private static void evaluate() {
StringBuilder finalStr = new StringBuilder();
System.out.println("Enter an expression to evaluate:");
String expr = scanner.nextLine();
if(isProperExpression(expr)) {
expr = replaceBefore(expr);
char[] temp = expr.toCharArray();
String operators = "(+-*/%)";
for(int i = 0; i < temp.length; i++) {
if((i == 0 && temp[i] != '*') || (i == temp.length-1 && temp[i] != '*' && temp[i] != '!')) {
finalStr.append(temp[i]);
} else if((i > 0 && i < temp.length -1) || (i==temp.length-1 && temp[i] == '!')) {
if(temp[i] == '!') {
StringBuilder str = new StringBuilder();
for(int k = i-1; k >= 0; k--) {
if(Character.isDigit(temp[k])) {
str.insert(0, temp[k] );
} else {
break;
}
}
Long prev = Long.valueOf(str.toString());
BigInteger val = new BigInteger("1");
for(Long j = prev; j > 1; j--) {
val = val.multiply(BigInteger.valueOf(j));
}
finalStr.setLength(finalStr.length() - str.length());
finalStr.append("(" + val + ")");
if(temp.length > i+1) {
char next = temp[i+1];
if(operators.indexOf(next) == -1) {
finalStr.append("*");
}
}
} else {
finalStr.append(temp[i]);
}
}
}
expr = finalStr.toString();
if(expr != null && !expr.isEmpty()) {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
try {
System.out.println("Result: " + engine.eval(expr));
evaluate();
} catch (ScriptException e) {
System.out.println(e.getMessage());
}
} else {
System.out.println("Please give an expression");
evaluate();
}
} else {
System.out.println("Not a valid expression");
evaluate();
}
}
private static String replaceBefore(String expr) {
expr = expr.replace("(", "*(");
expr = expr.replace("+*", "+").replace("-*", "-").replace("**", "*").replace("/*", "/").replace("%*", "%");
return expr;
}
private static boolean isProperExpression(String expr) {
expr = expr.replaceAll("[^()]", "");
char[] arr = expr.toCharArray();
Stack<Character> stack = new Stack<Character>();
int i =0;
while(i < arr.length) {
try {
if(arr[i] == '(') {
stack.push(arr[i]);
} else {
stack.pop();
}
} catch (EmptyStackException e) {
stack.push(arr[i]);
}
i++;
}
return stack.isEmpty();
}
}
Please find the updated gist anytime here. Also comment if any issues are there. Thanks.
There are some perfectly capable answers here. However for non-trivial script it may be desirable to retain the code in a cache, or for debugging purposes, or even to have dynamically self-updating code.
To that end, sometimes it's simpler or more robust to interact with Java via command line. Create a temporary directory, output your script and any assets, create the jar. Finally import your new code.
It's a bit beyond the scope of normal eval() use in most languages, though you could certainly implement eval by returning the result from some function in your jar.
Still, thought I'd mention this method as it does fully encapsulate everything Java can do without 3rd party tools, in case of desperation. This method allows me to turn HTML templates into objects and save them, avoiding the need to parse a template at runtime.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
class Calculate {
public static void main(String[] args) {
String strng = "8*-2*3*-1*10/2+6-2";
String[] oparator = {"+","-","*","/"};
List<String> op1 = new ArrayList<>();
String[] x = strng.split("");
int sayac=0;
for (String i : x) {
sayac ++;
for (String c : oparator) {
if (i.equals(c)) {
try {
int j = Integer.parseInt(strng.substring(0, sayac - 1));
op1.add(strng.substring(0, sayac - 1));
op1.add(c);
strng = strng.substring(sayac);
sayac = 0;
}catch (Exception e)
{
continue;
}
}
}
}
op1.add(strng);
ListIterator<String> it = op1.listIterator();
List<List> newlist = new ArrayList<>() ;
while (it.hasNext()) {
List<String> p= new ArrayList<>();
p.add(String.valueOf(it.nextIndex()));
p.add(it.next());
newlist.add(p);
}
int sayac2=0;
String oparatorvalue = "*";
calculate(sayac2,newlist,oparatorvalue);
String oparatorvalue2 = "/";
calculate(sayac2,newlist,oparatorvalue2);
String oparatorvalue3 = "+";
calculate(sayac2,newlist,oparatorvalue3);
String oparatorvalue4 = "-";
calculate(sayac2,newlist,oparatorvalue4);
System.out.println("Result:"+newlist.get(0).get(1));
}
private static void calculate(int sayac2, List<List> newlist, String oparatorvalue) {
while (sayac2<4){
try{
for (List j : newlist) {
if (j.get(1) == oparatorvalue) {
Integer opindex = newlist.indexOf(j);
Object sayi1 = newlist.get(opindex - 1).get(1);
Object sayi2 = newlist.get(opindex + 1).get(1);
int sonuc=0;
if (oparatorvalue.equals("*")){
sonuc = Integer.parseInt(sayi1.toString()) * Integer.parseInt(sayi2.toString());
}
if (oparatorvalue.equals("/")){
sonuc = Integer.parseInt(sayi1.toString()) / Integer.parseInt(sayi2.toString());
}
if (oparatorvalue.equals("+")){
sonuc = Integer.parseInt(sayi1.toString()) + Integer.parseInt(sayi2.toString());
}
if (oparatorvalue.equals("-")){
sonuc = Integer.parseInt(sayi1.toString()) - Integer.parseInt(sayi2.toString());
}
newlist.remove(opindex - 1);
newlist.remove(opindex - 1);
newlist.remove(opindex - 1);
List<String> sonuclist = new ArrayList<>();
sonuclist.add(String.valueOf(opindex - 1));
sonuclist.add(String.valueOf(sonuc));
newlist.add(opindex - 1, sonuclist);
}}}
catch (Exception e){
continue;
}
sayac2++;}
}
}
If you do not want to import heavy scripting library, you can use SimpleExpressionEvaluator directly into your code
Usage:
Expression.eval("1+2").asString(); // returns "3.0"
Expression.eval("1+2").asInt(); // returns 3
Expression.eval("2>3").asString(); // returns "false"
Expression.eval("2>3").asBoolean(); // returns false
Expression.eval("(3>2)||((2<4)&&(2>1))").asString(); // returns "true"
With variables:
HashMap<String, Object> st = new HashMap<String, Object>();
st.put("a",1);
st.put("b",2);
st.put("c",3);
st.put("d",4);
Expression.eval("a+b", st).asInt(); // or simply asString()
Expression.eval("a>b",st).asBoolean(); // or simply asString()
Expression.eval("(c>b)||((b<d)&&(b>a))",st).asBoolean(); // or simply asString()
Expression.eval("(c>2)||((2<d)&&(b>1))",st).asBoolean(); // or simply asString()
Using ExpressionBuilder:
Expression.expressionBuilder().putSymbol("a",2).putSymbol("b",3).build("(b>a)").evaluate()
The following resolved the issue:
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String str = "4*5";
System.out.println(engine.eval(str));

Converting multiple strings into one

I'm trying to convert multiple strings into one simple dialogue from a NPC. Basically what I'm trying to do is make a list of all the skills a player has 200M experience in and output it into a NPC dialogue.
OLD
if (componentId == OPTION_4) {
sendNPCDialogue(npcId, 9827, "You can prestige: "+maxedSkills()+"");
}
private String maxedSkills() {
return ""+attackMax()+""+strengthMax()+""+defenceMax()+"";
}
public String attackMax() {
if (player.getSkills().getXp(Skills.ATTACK) == 200000000)
return "Attack, ";
else
return "";
}
public String strengthMax() {
if (player.getSkills().getXp(Skills.STRENGTH) == 200000000)
return "Strength, ";
else
return "";
}
public String defenceMax() {
if (player.getSkills().getXp(Skills.DEFENCE) == 200000000)
return "Defence, ";
else
return "";
}
With that code I have it working, but that is a lot of code to add due to there being 25 different skills. How would I create a way to make all of the skills be referenced into one? Here are all of the skill names:
public static final String[] SKILL_NAME = { "Attack", "Defence", "Strength", "Constitution", "Ranged", "Prayer",
"Magic", "Cooking", "Woodcutting", "Fletching", "Fishing", "Firemaking", "Crafting", "Smithing", "Mining",
"Herblore", "Agility", "Thieving", "Slayer", "Farming", "Runecrafting", "Hunter", "Construction",
"Summoning", "Dungeoneering" };
New and working (for attack/strength/defence):
public static final int[] SKILL_TYPE = {Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE};
public String maxedSkills() {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < SKILL_TYPE.length; i++) {
if (player.getSkills().getXp(i) == 200000000) {
if(sb.length()>0) sb.append(", ");
sb.append(Skills.SKILL_NAME[i]);
}
}
if(sb.length()>0) sb.append(".");
return sb.toString();
}
Simplest way would be to have a parameteried method that takes the Skill type as input. Here is how it would look like:
public String skillMax(Skills skill) {
if (player.getSkills().getXp(skill) == 200000000)
return skill.getName() + ", ";
else
return "";
}
The next thing to do is to provide a name to the skill in Skills enum. Something like this should work:
public enum Skills {
DEFENSE("Defense"), ...;
private String name;
Skills(String name) { this.name = name; }
String getName() { return this.name; }
}
Use a StringBuffer (thread safe) or a StringBuilder and do something like this.
....
public static final Skills[] SKILL_TYPE = {Skills.Attack, Skills.Defence, ...};
public String getBigString() {
StringBuffer sb = new StringBuffer();
int nSkills = 0, lSkill = 0;
for( int i = 0; i < SKILL_TYPE.length; i++ )
{
if( player.getSkills().getXp(SKILL_TYPE[i]) == K_SOMELEVEL ) {
if(nSkills > 0) sb.append(", ");
lSkill = sb.length(); // track position of last skill in string
nSkills += 1;
sb.append(SKILL_NAME[i]);
}
}
if( nSkills > 0 )
{
if( nSkills > 1 ) sb.insert( lSkill, "and ");
sb.append(".");
}
return sb.toString();
}

Helper Method won't work when called from other method, but will from main

I have a helper method that I am calling from another method in the same class. When I test it from main, it works fine. But as soon as I use it in the other class, it doesn't work at all. I cannot figure out what is wrong.
This is the helper method:
private boolean checkStack(Stack<String> stack,String check) {
System.out.println(stack);
System.out.println(check);
Stack<String> jump = new Stack<String>();
int count = 0;
String temp = "";
while (!stack.empty()) {
temp = stack.pop();
if (check == temp) {
count++;
}
jump.push(temp);
}
while (!jump.empty()) {
temp = jump.pop();
stack.push(temp);
}
System.out.println(count);
if (count != 0) {
return true;
} else {
return false;
}
}
I will test it from main like so:
pathSoFar.push("00");
pathSoFar.push("01");
pathSoFar.push("20");
pathSoFar.push("23");
System.out.println(pathSoFar);
String checkfor = "20";
System.out.println(test01.checkStack(pathSoFar,checkfor));
But it wont work when I call it from another method:
for (String n : possibleSpots) {
System.out.println();
String check = n;
if (!checkStack(pathSoFar, n)) {
pathSoFar.push(n);
String x = ""+n.charAt(0);
String y = ""+n.charAt(1);
int nextRow = Integer.parseInt(x);
int nextCol = Integer.parseInt(y);
System.out.println(nextRow + "" + nextCol + " = next move.");
if (findPath(wordToFind, pathSoFar, nextRow, nextCol)) {
return true;
}
} else{}
}
This is the method header if that helps:
private boolean findPath(String wordToFind, Stack<String> pathSoFar, int row, int col) {
possibleSpots can contain either String literals or String objects.
The problem lies in the following line
if (check == temp)
Change it to
if (check.equals(temp))
String matching is done with == which will work only for String literals.
That is the reason why it worked for you in one case and it does not work in another case.
To know the difference check the below link:
What is the difference between == vs equals() in Java?

Android - Loop and filter on List?

I have a List of data like this :
I need to get first and last records are same :
And my model is :
public class Modeltest {
private String lat;
private String lng;
private String date;
private String firstTime;
private String lasttime;
private String counts;
private String userCode;
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
.......
.....
.....
}
I can getting first and last :
List<Unprocessed_DistanceTime_D> listCDM = QDB.DistanceSelect_D();
int count = 1;
boolean flag = true;
int index;
for (int i = 0; i < listCDM.size() - 1; i++) {
if (listCDM.get(count).getDate().equalsIgnoreCase(listCDM.get(i).getDate()) &&
listCDM.get(count).getLat().equalsIgnoreCase(listCDM.get(i).getLat()) &&
listCDM.get(count).getLng().equalsIgnoreCase(listCDM.get(i).getLng()) &&
listCDM.get(count).getCounts().equalsIgnoreCase(listCDM.get(i).getCounts())) {
if (flag){
index = i;
flag = false;
}
}else {
index = i;
flag = true;
}
count++;
}
}
But my problem is here. How I can add these in another list and add single records in it ?
I get the first and last record then add in another list (I wrote the model above) .
I should fill my list here :
if (flag){
index = i;
///HERE
flag = false;
}
}else {
index = i;
///HERE
flag = true;
}
Here's a brute force method that first groups all the entries by a locally defined Identity and than merge those groups into a single Modeltest object.
There is probably a better way to do this though, since this disregards the fact that the input data is sorted.
List<Unprocessed_DistanceTime_D> list = ...;
class Identity {
private final String lat;
private final String lng;
private final String date;
private final String counts;
public Identity(Unprocessed_DistanceTime_D model) {
this.lat = model.getLat();
this.lng = model.getLng();
this.date = model.getDate();
this.counts = model.getCounts();
}
#Override
public int hashCode() {
int code = 0;
code ^= lat.hashCode();
code ^= lng.hashCode();
code ^= date.hashCode();
code ^= counts.hashCode();
return code;
}
#Override
public boolean equals(Object other) {
if(other == null)
return false;
if(!(other instanceof Identity))
return false;
Identity io = (Identity) other;
return lat.equalsIgnoreCase(io.lat)
&& lng.equalsIgnoreCase(io.lng)
&& date.equalsIgnoreCase(io.date)
&& counts.equalsIgnoreCase(io.counts);
}
}
List<Modeltest> models = list.stream()
.collect(Collectors.groupingBy(Identity::new))
.values().stream()
.map(group -> { // Convert groups into single Modeltest
if(group.size() == 1) { // Case for single entries
Unprocessed_DistanceTime_D e = group.get(0);
return new Modeltest(e.getLat(), e.getLng(), e.getDate(), e.getTime(),
e.getTime(), e.getCounts(), e.getUserCode());
}
// Case for more entries
group.sort(Comparator.comparing(Unprocessed_DistanceTime_D::getTime));
Unprocessed_DistanceTime_D first = group.get(0);
Unprocessed_DistanceTime_D last = group.get(group.size() - 1);
return new Modeltest(first.getLat(), first.getLng(), first.getDate(),
first.getTime(), last.getTime(), first.getCounts(), first.getUserCode());
})
.collect(Collectors.toList());
Here’s an idea for an algorithm. You can probably modify to your needs and fill in the details.
List<Unprocessed_DistanceTime_D> newListCDM = new ArrayList<>();
if (! listCDM.isEmpty()) {
Unprocessed_DistanceTime_D firstInGroup = listCDM.get(0);
Unprocessed_DistanceTime_D lastInGroup = firstInGroup;
for (int i = 1; i < listCDM.size() - 1; i++) {
Unprocessed_DistanceTime_D current = listCDM.get(i);
if (inSameGroup(firstInGroup, current)) { // current belongs to the same group
lastInGroup = current;
} else { // new group
// add old group to new list
newListCDM.add(firstInGroup);
if (lastInGroup != firstInGroup) {
newListCDM.add(lastInGroup);
}
}
}
// add last group to new list
newListCDM.add(firstInGroup);
if (lastInGroup != firstInGroup) {
newListCDM.add(lastInGroup);
}
}

"Duplicate" entries in ArrayList?

i have this class thats going to fill a list with All employees that are pre made in an array. I can populate an ArrayList with employees but the only problem is that i get a few "Duplicate" entries, i use quotes cause they are not EXACTLY the same but they could share the same name or employee number but may not have the same hire year or salary ect.
heres the employee class :
public class Employee {
public String EmployeeName;
public String EmployeeNumber;
public int hireyear;
public double WeeklyEarning;
public Employee()
{
EmployeeName = null;
EmployeeNumber = null;
hireyear = 0;
WeeklyEarning = 0;
}
public static final String[] Empnum = new String[] {
"0001-A", "0002-B","0003-C","0004-D","0002-A",
"0003-B","0004-C","0005-D","0011-A", "0012-B",
"0013-C","0014-D","0121-A", "0122-B","0123-C",
"0321-A", "0312-B","1234-D","4321-C","1122-D"};
public static final String[] Ename = new String[] {
"Josh", "Alex", "Paul", "Jimmy", "Josh", "Gordan", "Neil", "Bob",
"Shiv", "James", "Jay", "Chris", "Michael", "Andrew", "Stuart",
"Dave","Benjamin","Dan","Brian","Michelle"};
public String getEmployeeName()
{
return this.EmployeeName;
}
public String getEmployeeNumber()
{
return this.EmployeeNumber;
}
public int gethireyear()
{
return this.hireyear;
}
public double getWeeklyEarning()
{
return this.WeeklyEarning;
}
public String setEmployeeName(String EName)
{
return this.EmployeeName = EName;
}
public String setEmployeeNumber(String ENumber)
{
return this.EmployeeNumber = ENumber;
}
public int setEmployeehireyear(int Ehireyear)
{
return this.hireyear = Ehireyear;
}
public double setEmployeeweeklyearning(double Eweeklyearning)
{
return this.WeeklyEarning = Eweeklyearning;
}
public String toString(){
String data = "\n Employee Name : " + EmployeeName + " \n Employee Number: " + EmployeeNumber + " \n Hire Year : " + hireyear + "\n Weekly Earnings : " + WeeklyEarning;
return data;
}
public boolean equals(Object o){
if(this == null){
return false;
}
if(this == o){
return true;
}
if(!(o instanceof Employee)){
return false;
}
Employee temp = (Employee) o;
if(this.getEmployeeName().equals(temp.getEmployeeName())){
return true;
}
if(this.getEmployeeNumber().equals(temp.getEmployeeNumber())){
return true;
}
if(this.gethireyear() == temp.gethireyear()){
return true;
}
if(this.getWeeklyEarning() == temp.getWeeklyEarning()){
return true;
}
return false;
}
}
Heres the generateList method that will populate the list:
public ArrayList<Employee> generateEmpList(){
empList = new ArrayList <Employee>();
Random empPicker = new Random();
for(int i = 0; i < 20; i++){
int id = empPicker.nextInt(20);
if(id < 12) // roll for production worker
{
//System.out.println("Adding Production Worker");
ProductionWorker temp = new ProductionWorker();
temp = temp.generateProductionWorker();
prodWorker = temp;
empList.add(prodWorker);
}
else //roll for Shift supervisor
{
//System.out.println("Adding Shift supervisor");
ShiftSupervisor supervisor = new ShiftSupervisor();
supervisor = supervisor.generateShiftSupervisor();
shiftWorker = supervisor;
empList.add(shiftWorker);
}
}
Iterator iterator = empList.iterator();
while (iterator.hasNext()) {
System.out.println("");
System.out.println(iterator.next());
}
return empList;
}
and also which could be helpful is the "generateProductionWorker()" and shiftSupervisor methods - to keep it short ill only post prod worker method cause they are basically the same:
public ProductionWorker generateProductionWorker(){
Random rng = new Random();
int numberOfEmployeeNames = Ename.length;
ProductionWorker tempPworker = new ProductionWorker();
String employeeName = Ename[rng.nextInt(numberOfEmployeeNames)];
tempPworker.setEmployeeName(employeeName);
int numberOfEmployeeNumbers = Empnum.length;
String employeeNumber = Empnum[rng.nextInt(numberOfEmployeeNumbers)];
tempPworker.setEmployeeNumber(employeeNumber);
int yearHired = rng.nextInt(35) + 1980;
tempPworker.setEmployeehireyear(yearHired);
double weeklySalary = rng.nextInt((100) * 100);
tempPworker.setEmployeeweeklyearning(weeklySalary);
int hourlyRate = rng.nextInt(20) + 10;
tempPworker.setHourlyRate(hourlyRate);
return tempPworker;
}
I'm sure I'm missing something trivial but any ideas why i get similar entries when i have a list of 20 names and numbers?
ex:
empname - josh
empnum - 0000-A
hireyear - 1994
salary - 40,000
empname - josh
empnum - 0000-A
hireyear - 1999
salary - 60,500
any advice would help, Thanks!
Look at the equals method in your Employee class. If their name are the same, you return true, which means these are equals. The same is for the other attributes. You must replace your if statements.
I agree with Georgi, you equals method is the culprit.
Currently it is returning true after the first if statement at the line that reads
if(this.getEmployeeName().equals(temp.getEmployeeName())){
return true;
}
Because it is a return statement it stops the method from continuing to the other statements. You might try this:
public boolean equals(Object o){
if(this == null){
return false;
}
if(this == o){
return true;
}
if(!(o instanceof Employee)){
return false;
}
//set all the elements in the array to false and change to true when true.
boolean [] doesItMatch = new boolean[4];
doesItMatch[0] = false;
doesItMatch[1] = false;
doesItMatch[2] = false;
doesItMatch[3] = false;
Employee temp = (Employee) o;
if(this.getEmployeeName().equals(temp.getEmployeeName())){
doesItMatch[0] = true;
}
if(this.getEmployeeNumber().equals(temp.getEmployeeNumber())){
doesItMatch[1] = true;
}
if(this.gethireyear() == temp.gethireyear()){
doesItMatch[2] = true;
}
if(this.getWeeklyEarning() == temp.getWeeklyEarning()){
doesItMatch[3] = true;
}
int check = 0;
//Now that you have checked all the values, check the array. Using a simple counter.
for(int i = 0; i < doesItMatch.length; i++){
if(doesItMatch[i]){
check++;
} else {
check--;
}
}
//The counter should be 4 when the if statements above are all true. Anything else is false.
if(check == 4){
return true;
} else {
return false;
}
}
This method now checks each of the attributes in the Employee class. (Name, Number, Hire year and so on. If you create more attributes to the class it is easy to add more elements to the array just be sure to set them to false.)
Hope this helps
This also would take a little maintenance if you expanded the Employee class so you might want to find a way to make it a little easier on yourself.

Categories