Searching an Array for a combination of letters and numbers - java

I'm a first year programmer.
I've been trying to search an array which has stored four variables, with an input.
All of the examples I've found make use of int, and searches for a number within a list.
My program must search for a combination of letters and numbers. (Ex. COP 2800)
import java.util.Scanner;
public class courseInfo {
public static int courseInfo(int[] list, int key) {
Scanner input = new Scanner(System.in);
// Input course name
System.out.print("Enter course name: (Ex. COP 2800) ");
double courseInput = input.nextDouble();
for (int i = 0; i < list.length; i++) {
if (key == list[i])
return i;
}
return -1;
}
public static void main(String[] args) {
int[] list = {COP 2800, PSY 1012, EVR 2001, COP 1000};
System.out.println(linearSearch(list, courseInput));
}
}
Please use layman's terms, I've only been in this class for three weeks.
If I remove COP, PSY, EVR, and COP from line 21, I return a different error;
courseInfo.java:22: error: cannot find symbol
System.out.println(linearSearch(list, courseInput));
^
symbol: variable courseInput
location: class courseInfo
1 error

You are checking an equals condition on String values with a courseInput which is supposed to be an int.
Also, You are returning -1 for whatever happens in the if condition. Are you supposed to return -1 if the value of key doesn't equal the one in the list?
Also the courseInput variable is local to the method. Make it global by declaring it in the class as a member variable.

You have double courseInput = input.nextDouble(), which will only accept doubles, not characters. You also have int[] list, which is an array of integers, so it cannot hold characters either. You'll have better luck if you put the whole course name (both letters and numbers) into a String. Then you can scan an entire line and store it in an array of Strings.

I suggest you do a bit more work on the basic data types of Java before attempting this. Java is a fairly strictly typed language which means that in general (there are plenty of exceptions) you need to decide what type of value you are storing in a variable ahead of time. You are mixing many types in your code: integers, doubles and strings.
So start by deciding if a course's identifier is a number of a name. If it's a number you can use an int to store it. If it's a name you can use a String. You note that a subject includes letters and numbers. But as long as you don't need to compare the numbers directly then you can store the entire identifier in a String. There's no need to split them up.
Another common trap for new starters is that primitive types (such as int) behave quite differently than objects (such as String). An immediate difference is the meaning of ==. For primitive types it compares the values while for objects it checks if the left and right side refer to the same object.
I suspect you want your subjects to be identified by name (i.e. String). In which case your code might look something like:
String[] subjects = {"COP2800", "PSY1012", "EVR2001"};
and
for (int i = 0; i < subjects.length; i++) {
if (subjects[i].equals(name))
return i;
}
return -1;

Related

Comparing two char arrays in Java

I am trying to compare two char arrays lexicographically, using loops and arrays only. I solved the task, however, I think my code is bulky and unnecessarily long and would like an advice on how to optimize it. I am a beginner. See code below:
//Compare Character Arrays Lexicographically
//Write a program that compares two char arrays lexicographically (letter by letter).
// Research how to convert string to char array.
Scanner scanner = new Scanner(System.in);
String word1 = scanner.nextLine();
String word2 = scanner.nextLine();
char[] firstArray = word1.toCharArray();
char[] secondArray = word2.toCharArray();
for (char element : firstArray) {
System.out.print(element + " ");
}
System.out.println();
for (char element : secondArray) {
System.out.print(element + " ");
}
System.out.println();
String s = String.valueOf(firstArray);
String b = String.valueOf(secondArray);
int result = s.compareTo(b);
if (result < 0) {
System.out.println("First");
} else if (result > 0) {
System.out.println("Second");
} else {
System.out.println("Equal");
}
}
}
I think its pretty normal. You've done it right. There's not much code to reduce here , best you can do is not write the two for loops to print the char arrays. Or if you are wanting to print the two arrays then maybe use System.out.println(Arrays.toString(array_name)); instead of two full dedicated for/for each loops. It does the same thing in the background but makes your code look a little bit cleaner and that's what you are looking for.
As commented by tgdavies, you schoolwork assignment was likely intended for you to compare characters in your own code rather than call String#compareTo.
In real life, sorting words alphabetically is quite complex because of various cultural norms across various languages and dialects. For real work, we rely on collation tools rather than write our own sorting code. For example, an e with the diacritical ’ may sort before or after an e without, depending on the cultural context.
But for a schoolwork assignment, the goal of the exercise is likely to have you compare each letter of each word by examining its code point number, the number assigned to identify each character defined in Unicode. These code point numbers are assigned by Unicode in roughly alphabetical order. This code point number ordering is not sufficient to do sorting in real work, but is presumably good enough for your assignment, especially for text using only basic American English using letters a-z/A-Z.
So, if the numbers are the same, move to the next character in each word. When you reach the nth letter that are not the same in both, then in overly simplistic terms, you know which comes after which alphabetically. If all the numbers are the same, the words are the same.
Another real world problem is the char type has been legacy since Java 5, essentially broken since Java 2. As a 16-bit value, char is physically incapable of representing most characters.
So instead of char arrays, use int arrays to hold code point integer numbers.
int[] firstWordCodePoints = firstWord.codePoints().toArray() ;

Questions regarding programming a single-line calculator in Java

I am currently a early CS student and have begun to start projects outside of class just to gain more experience. I thought I would try and design a calculator.
However, instead of using prompts like "Input a number" etc. I wanted to design one that would take an input of for example "1+2+3" and then output the answer.
I have made some progress, but I am stuck on how to make the calculator more flexible.
Scanner userInput = new Scanner(System.in);
String tempString = userInput.nextLine();
String calcString[] = tempString.split("");
Here, I take the user's input, 1+2+3 as a String that is then stored in tempString. I then split it and put it into the calcString array.
This works out fine, I get "1+2+3" when printing out all elements of calcString[].
for (i = 0; i <= calcString.length; i += 2) {
calcIntegers[i] = Integer.parseInt(calcString[i]);
}
I then convert the integer parts of calcString[] to actual integers by putting them into a integer array.
This gives me "1 0 2 0 3", where the zeroes are where the operators should eventually be.
if (calcString[1].equals("+") && calcString[3].equals("+")) {
int retVal = calcIntegers[0] + calcIntegers[2] + calcIntegers[4];
System.out.print(retVal);
}
This is where I am kind of stuck. This works out fine, but obviously isn't very flexible, as it doesn't account for multiple operators at the same like 1 / 2 * 3 - 4.
Furthermore, I'm not sure how to expand the calculator to take in longer lines. I have noticed a pattern where the even elements will contain numbers, and then odd elements contain the operators. However, I'm not sure how to implement this so that it will convert all even elements to their integer counterparts, and all the odd elements to their actual operators, then combine the two.
Hopefully you guys can throw me some tips or hints to help me with this! Thanks for your time, sorry for the somewhat long question.
Create the string to hold the expression :
String expr = "1 + 2 / 3 * 4"; //or something else
Use the String method .split() :
String tokens = expr.split(" ");
for loop through the tokens array and if you encounter a number add it to a stack. If you encounter an operator AND there are two numbers on the stack, pop them off and operate on them and then push back to the stack. Keep looping until no more tokens are available. At the end, there will only be one number left on the stack and that is the answer.
The "stack" in java can be represented by an ArrayList and you can add() to push items onto the stack and then you can use list.get(list.size()-1); list.remove(list.size()-1) as the pop.
You are taking input from user and it can be 2 digit number too.
so
for (i = 0; i <= calcString.length; i += 2) {
calcIntegers[i] = Integer.parseInt(calcString[i]);
}
will not work for 2 digit number as your modification is i+=2.
Better way to check for range of number for each char present in string. You can use condition based ASCII values.
Since you have separated your entire input into strings, what you should do is check where the operations appear in your calcString array.
You can use this regex to check if any particular String is an operation:
Pattern.matches("[+-[*/]]",operation )
where operation is a String value in calcString
Use this check to seperate values and operations, by first checking if any elements qualify this check. Then club together the values that do not qualify.
For example,
If user inputs
4*51/6-3
You should find that calcString[1],calcString[4] and calcString[6] are operations.
Then you should find the values you need to perform operations on by consolidating neighboring digits that are not separated by operations. In the above example, you must consolidate calcString[2] and calcString[3]
To consolidate such digits you can use a function like the following:
public int consolidate(int startPosition, int endPosition, ArrayList list)
{
int number = list.get(endPosition);
int power = 10;
for(int i=endPosition-1; i>=startPosition; i--)
{
number = number + (power*(list.get(i)));
power*=10;
}
return number;
}
where startPosition is the position where you encounter the first digit in the list, or immediately following an operation,
and endPosition is the last position in the list till which you have not encountered another operation.
Your ArrayList containing user input must also be passed as an input here!
In the example above you can consolidate calcString[2] and calcString[3] by calling:
consolidate(2,3,calcString)
Remember to verify that only integers exist between the mentioned positions in calcString!
REMEMBER!
You should account for a situation where the user enters multiple operations consecutively.
You need a priority processing algorithm based on the BODMAS (Bracket of, Division, Multiplication, Addition and Subtraction) or other mathematical rule of your preference.
Remember to specify that your program handles only +, -, * and /. And not power, root, etc. functions.
Take care of the data structures you are using according to the range of inputs you are expecting. A Java int will handle values in the range of +/- 2,147,483,647!

What should be the logic of hashfunction() in order to check that two strings are anagrams or not?

I want to write a function that takes string as a parameter and returns a number corresponding to that string.
Integer hashfunction(String a)
{
//logic
}
Actually the question im solving is as follows :
Given an array of strings, return all groups of strings that are anagrams. Represent a group by a list of integers representing the index in the original list.
Input : cat dog god tca
Output : [[1, 4], [2, 3]]
Here is my implementation :-
public class Solution {
Integer hashfunction(String a)
{
int i=0;int ans=0;
for(i=0;i<a.length();i++)
{
ans+=(int)(a.charAt(i));//Adding all ASCII values
}
return new Integer(ans);
}
**Obviously this approach is incorrect**
public ArrayList<ArrayList<Integer>> anagrams(final List<String> a) {
int i=0;
HashMap<String,Integer> hashtable=new HashMap<String,Integer>();
ArrayList<Integer> mylist=new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> answer=new ArrayList<ArrayList<Integer>>();
if(a.size()==1)
{
mylist.add(new Integer(1));
answer.add(mylist);
return answer;
}
int j=1;
for(i=0;i<a.size()-1;i++)
{
hashtable.put(a.get(i),hashfunction(a.get(i)));
for(j=i+1;j<a.size();j++)
{
if(hashtable.containsValue(hashfunction(a.get(j))))
{
mylist.add(new Integer(i+1));
mylist.add(new Integer(j+1));
answer.add(mylist);
mylist.clear();
}
}
}
return answer;
}
}
Oh boy... there's quite a bit of stuff that's open for interpretation here. Case-sensitivity, locales, characters allowed/blacklisted... There are going to be a lot of ways to answer the general question. So, first, let me lay down a few assumptions:
Case doesn't matter. ("Rat" is an anagram of "Tar", even with the capital lettering.)
Locale is American English when it comes to the alphabet. (26 letters from A-Z. Compare this to Spanish, which has 28 IIRC, among which 'll' is considered a single letter and a potential consideration for Spanish anagrams!)
Whitespace is ignored in our definition of an anagram. ("arthas menethil" is an anagram of "trash in a helmet" even though the number of whitespaces is different.)
An empty string (null, 0-length, all white-space) has a "hash" (I prefer the term "digest", but a name is a name) of 1.
If you don't like any of those assumptions, you can modify them as you wish. Of course, that will result in the following algorithm being slightly different, but they're a good set of guidelines that will make the general algorithm relatively easy to understand and refactor if you wish.
Two strings are anagrams if they are exhaustively composed of the same set of characters and the same number of each included character. There's a lot of tools available in Java that makes this task fairly simple. We have String methods, Lists, Comparators, boxed primitives, and existing hashCode methods for... well, all of those. And we're going to use them to make our "hash" method.
private static int hashString(String s) {
if (s == null) return 0; // An empty/null string will return 0.
List<Character> charList = new ArrayList<>();
String lowercase = s.toLowerCase(); // This gets us around case sensitivity
for (int i = 0; i < lowercase.length(); i++) {
Character c = Character.valueOf(lowercase.charAt(i));
if (Character.isWhitespace(c)) continue; // spaces don't count
charList.add(c); // Note the character for future processing...
}
// Now we have a list of Characters... Sort it!
Collections.sort(charList);
return charList.hashCode(); // See contract of java.util.List#haschCode
}
And voila; you have a method that can digest a string and produce an integer representing it, regardless of the order of the characters within. You can use this as the basis for determining whether two strings are anagrams of each other... but I wouldn't. You asked for a digest function that produces an Integer, but keep in mind that in java, an Integer is merely a 32-bit value. This method can only produce about 4.2-billion unique values, and there are a whole lot more than 4.2-billion strings you can throw at it. This method can produce collisions and give you nonsensical results. If that's a problem, you might want to consider using BigInteger instead.
private static BigInteger hashString(String s) {
BigInteger THIRTY_ONE = BigInteger.valueOf(31); // You should promote this to a class constant!
if (s == null) return BigInteger.ONE; // An empty/null string will return 1.
BigInteger r = BigInteger.ONE; // The value of r will be returned by this method
List<Character> charList = new ArrayList<>();
String lowercase = s.toLowerCase(); // This gets us around case sensitivity
for (int i = 0; i < lowercase.length(); i++) {
Character c = Character.valueOf(lowercase.charAt(i));
if (Character.isWhitespace(c)) continue; // spaces don't count
charList.add(c); // Note the character for future processing...
}
// Now we have a list of Characters... Sort it!
Collections.sort(charList);
// Calculate our bighash, similar to how java's List interface does.
for (Character c : charList) {
int charHash = c.hashCode();
r=r.multiply(THIRTY_ONE).add(BigInteger.valueOf(charHash));
}
return r;
}
You need a number that is the same for all strings made up of the same characters.
The String.hashCode method returns a number that is the same for all strings made up of the same characters in the same order.
If you can sort all words consistently (for example: alphabetically) then String.hashCode will return the same number for all anagrams.
return String.valueOf(Arrays.sort(inputString.toCharArray())).hashCode();
Note: this will work for all words that are anagrams (no false negatives) but it may not work for all words that are not anagrams (possibly false positives). This is highly unlikely for short words, but once you get to words that are hundreds of characters long, you will start encountering more than one set of anagrams with the same hash code.
Also note: this gives you the answer to the (title of the) question, but it isn't enough for the question you're solving. You need to figure out how to relate this number to an index in your original list.

two dimensional array in java - difficulties

I'm used to python and django but I've recently started learning java. Since I don't have much time because of work I missed a lot of classes and I'm a bit confused now that I have to do a work.
EDIT
The program is suppose to attribute points according to the time each athlete made in bike and race. I have 4 extra tables for male and female with points and times.
I have to compare then and find the corresponding points for each time (linear interpolation).
So this was my idea to read the file, and use an arrayList
One of the things I'm having difficulties is creating a two dimensional array.
I have a file similar to this one:
12 M 23:56 62:50
36 F 59:30 20:60
Where the first number is an athlete, the second the gender and next time of different races (which needs to be converted into seconds).
Since I can't make an array mixed (int and char), I have to convert the gender to 0 and 1.
so where is what I've done so far:
public static void main(String[] args) throws FileNotFoundException {
Scanner fileTime = new Scanner (new FileReader ("time.txt"));
while (fileTime.hasNext()) {
String value = fileTime.next();
// Modify gender by o and 1, this way I'm able to convert string into integer
if (value.equals("F"))
value = "0";
else if (value.equals("M"))
value = "1";
// Verify which values has :
int index = valor.indexOf(":");
if (index != -1) {
String [] temp = value.split(":");
for (int i=0; i<temp.length; i++) {
// convert string to int
int num = Integer.parseInt(temp[i]);
// I wanted to multiply the first number by 60 to convert into seconds and add the second number to the first
num * 60; // but this way I multiplying everything
}
}
}
I'm aware that there's probably easier ways to do this but honestly I'm a bit confused, any lights are welcome.
Just because an array works well to store the data in one language does not mean it is the best way to store the data in another language.
Instead of trying to make a two dimensional array, you can make a single array (or collection) of a custom class.
public class Athlete {
private int _id;
private boolean _isMale;
private int[] _times;
//...
}
How you intend to use the data may change the way you structure the class. But this is a simple direct representation of the data line you described.
Python is a dynamically-typed language, which means you can think of each row as a tuple, or even as a list/array if you like. The Java idiom is to be stricter in typing. So, rather than having a list of list of elements, your Java program should define a class that represents a the information in each line, and then instantiate and populate objects of that class. In other words, if you want to program in idiomatic Java, this is not a two-dimensional array problem; it's a List<MyClass> problem.
Try reading the file line by line:
while (fileTime.hasNext())
Instead of hasNext use hasNextLine.
Read the next line instead of next token:
String value = fileTime.next();
// can be
String line = fileTime.nextLine();
Split the line into four parts with something as follows:
String[] parts = line.split("\\s+");
Access the parts using parts[0], parts[1], parts[2] and parts[3]. And you already know what's in what. Easily process them.

Why my parsing doesn't work?

I was asked for my homework to make a program wherein the user inputs a Roman numerals between 1-10 and outputs the decimal equivalent. Since I'll be getting a string in the input and an integer in the output, I parsed it, but it won't work. Any ideas why?
import java.util.Scanner ;
class Romans {
static Scanner s = new Scanner(System.in) ;
static String val = null ;
public static void main (String [] args)
{
System.out.print ("Enter a roman numeral between I to X: ");
String val = s.nextLine();
int e = Integer.parseInt(val);
}
static int getRoman (int e)
{
if (val = "I"){
System.out.print ("1") ;
}else if (val = "II" ){
System.out.print ("2") ;
}else if (val = "III") {
System.out.print ("3") ;
} else if (val = "IV") {
System.out.print ("4") ;
} else if (val = "V"){
System.out.print ("5");
} else if (val = "VI") {
System.out.print ("6");
} else if (val = "VII") {
System.out.print ("7");
} else if (val = "VIII") {
System.out.print ("8");
} else if (val = "IX") {
System.out.print ("9");
} else if (val = "X") {
System.out.print ("10") ;
}
return val ;
}
}
Two points:
= is the assignment operator, not the equality-testing operator (==)
You shouldn't use == to test for string equality anyway, as it will only test for reference equality; use equals to test whether two string references refer to equal (but potentially distinct) string objects.
Additionally, you're trying to return a String variable as an int, and you're not even calling getRoman...
I think we can tell you that the correct way to compare Strings is using equals().
You're doing assignments, to compare primitive types you've to use ==, to compare String the equals method.
Example:
if (val.equals("I"))
But also val is not present in the method getRoman().
You are trying to parse val as an int, but its not, its a character.
For such a small sample of chars, its probably easiest to simply create a lookup table, index it on the char.
Are you getting any errors?
In your code, you never call the getRoman function. Also, you're using the assignment operator = instead of the comparison operator "I".equals(val) for example.
String comparsion should be done with equals(String str) method instead of == comparison.
PS. You have = instead of == anyway.
The following statement is an assignment:
val = "I"
That is definitely not what you want to do here.
A comparison is done with the double equals, but double equals (==) compares references but you do not want to do that here either.
You want to use the equals method.
if (val.equals("I")) ...
Make those change everywhere and see how it works for you.
ACtually your main trouble comes from string comparison. In java, = is meant to assign values to variables, == is meant to compare values of primitive types and equals is the way to compare objects, especially for strings.
An alternative to using equals can be to use the JDK internal pool of strings, in this case, you could use == as a comparator.
In your case of parsing roman language numbers, you could also consider using a hashmap to store and retrieve effectively the parsed values of numbers. If you have thousands of comparisons like this to make, then go for identityhashmap.
And last, if you want to do real parsing for all roman numbers, not only the first ones, then you should considering using an automata, i.e. a state machine to parse numbers in a somewhat recursive way, that would be the more efficient model to apply to your problem.
The last 2 remarks are more oriented towards software algorithms, the first two ones are more oriented towards java syntax. You should start to know the syntax before going higher level optimizations.
Regards,
Stéphane
Aside from what was said above about how your String comparison should use the equals( ... ) function - for example,
if ( val.equals("VII") )
you also need to provide a return value for your function called getRoman. This function was declared as a function that returns an integer value to the caller, but in the implementation that you have provided, there are no return values (only System.out.println( ... )).
Also, you aren't inputting the correct parameter type - from what it looks like, your function is checking a String to see if it is a certain Roman numeral. So the correct function header would look like this:
public static int getRoman(String val)
Also, make sure you are actually calling this function in your main() - from what it looks like right now, you aren't even using the getRoman() function.
Hope this helps!

Categories