ArrayList Integer Sorting with Strings attached - java

I am trying to sort integers that are in an ArrayList, that part is working but I am also trying to keep a parallel array matched with the correct integer. I can't make them into a grouped object either. So if I had 3 words with 3 numbers (Numbers in an ArrayList and words in an ArrayList ("Hello" - 2, "The" - 5, "For" - 1). I would want For and 1 to come first, then Hello and to last would be The and 5. So It would carry over the word with the number. the code I have below is sorting Integers correctly but it seems that the words are being randomized.
void quickSort2 (ArrayList<Integer> list, int first, int last, ArrayList list2){
//Set first and last
int g = first, h = last;
int midIndex, dividingValue;
//middle values
midIndex = (first + last) / 2;
dividingValue = list.get(midIndex);
System.out.println("midIdex = "+midIndex + "first = "+first+"last = "+last);
//find if higher or lower
do{
while (list.get(g) < dividingValue) {
g++;
}
while (list.get(h) > dividingValue){
h--;
}
if (g <= h){
//Switch ints (Works)
int temp = list.get(g);
list.set(g,list.get(h));
list.set(h,temp);
g++;
h--;
//Switch Strings with the ints (Doesnt work)
ArrayList blah = new ArrayList();
blah.add(list2.get(g));
list2.set(g,list2.get(h));
list2.set(h,blah.get(0));
}
}
while (g<h);
//Back to the method
if(h>first) {
quickSort2(list, first, h, list2);
}
if(g<last) {
quickSort2(list, g, last, list2);
}
}

Maybe you should try switching the Strings before you increment the values of g and h... Also you don't need to create the Arraylist blah - just get the string like you do for the int
Something like this... I haven't looked to deeply into your code but this is most likely an error...
//Switch ints (Works)
int temp = list.get(g);
list.set(g,list.get(h));
list.set(h,temp);
// *** Don't increment here ***
// *** Switch Strings with the ints first ***
String tempStr = list2.get(g);
list2.set(g,list2.get(h));
list2.set(h,tempStr );
// *** Now increment ***
g++;
h--;

Here's a simple class to group an integer key and String together:
public class DataItem {
// These are the pieces of data each DataItem will carry around
private int key;
private String data;
// This is a constructor; if you say new DataItem(2,"Hello"), it creates an
// object whose key is 2 and data is "Hello"
public DataItem(int key, String data) {
this.key = key;
this.data = data;
}
// A method to get the object's key
public int getKey() {
return key;
}
// A method to get the object's data
public String getData() {
return data;
}
}
Now your quickSort2 method will take an ArrayList<DataItem> instead of an ArrayList<Integer>. When you use the get method on the ArrayList, it will return an entire DataItem instead of just an Integer. That means that if you want the integer, you'll need to call getKey() to get it. So instead of
dividingValue = list.get(midIndex);
you'd say
dividingValue = list.get(midIndex).getKey();
and instead of
while (list.get(g) < dividingValue) {
it would be
while (list.get(g).getKey() < dividingValue) {
The good news, though, is that when you switch the items, it will switch the entire DataItem, which means the String will stay with the integer, which is what you want. So under your "Switch ints" comment, change the type of temp from int to DataItem. Then your swap will swap everything.
(To make this even better, you can have DataItem implement Comparable<DataItem>, by adding a compareTo method that will compare one DataItem to another by comparing just the key fields. Then you can use built-in sort and other methods on arrays of DataItem. I'll let you read this tutorial yourself.)

Related

How do I add an object to a linked list in alphabetical order in Java?

I saw similar questions that included an index in the parameters, but my requirements don't allow me to do that. Assume the array is already sorted in alphabetical order.
This is my first time asking a question so sorry if I did something wrong.
public void addElement(Object element){
LinkedListIterator iterator = new LinkedListIterator();
int counter = 1;
int compare = 0;
if(first == null)
iterator.add(element);
else
{
while(iterator.hasNext())
{
compare = getElement(counter).toString().compareToIgnoreCase(element.toString());
//getElement is a method I made to retrieve an element from the linked list
//I have tested it and I know it works. Its parameter is an index
//toString() returns a String of what the element is. example: { Fruit }
//It is in that format with the brackets {}
if(compare != -1)
iterator.add(element);
else
{
iterator.next();
counter++;
}
}
}
}
Based on your question, I don't know exactly what you're using as a comparison value. Is it a string value within the object, the name of the object reference, etc? Assuming that you're inserting an object based on some sort of name variable, this is how you could do it.
Note: I'm sure you can find some sort of existing method/api that does this for you, but I'm assuming you'd like to see how it's done.
For this example, I created a class called AnyObject to iterate and compare. It looks like this:
AnyObject class
public class AnyObject {
private String name;
private int num;
private String color;
public AnyObject(String name, int num, String color) {
this.name = name;
this.num = num;
this.color = color;
}
#Override
public String toString() {
return name;
}
}
Using this simple class, we would modify your code so it looks like this:
AlphaInsertSort Class
import java.util.*;
public class AlphaInsertSort {
public static void main(String[] args) {
ArrayList<AnyObject> myList = new ArrayList<AnyObject>();
myList.add(new AnyObject("alphaObj", 44, "blue"));
myList.add(new AnyObject("betaObj", 7, "orange"));
myList.add(new AnyObject("gammaObj", 12, "red"));
myList.add(new AnyObject("omegaObj", 99, "yellow"));
printList(myList); //helps visualize what's going on
addElement(new AnyObject("charlieObj", 105, "purple"), myList);
printList(myList);
addElement(new AnyObject("aObj", 105, "purple"), myList);
printList(myList);
myList.add(new AnyObject("thetaObj", 0, "green"));
printList(myList);
addElement(new AnyObject("zetaObj", 2, "pink"), myList);
printList(myList);
System.out.println("Finished");
}
public static void addElement(AnyObject element, ArrayList<AnyObject> myList){
ListIterator<AnyObject> iterator = null;
//int counter = 1; don't need this
int compare = 0;
AnyObject current = myList.get(0); //changed name from first to current and will use this for comparison while iterating
iterator = myList.listIterator(); //this should set iterator to start of list. There's no constructor for listIterator
System.out.println("\ncurrent is " + current.toString());
if(current == null)
iterator.add(element);
else
{
while(iterator.hasNext())
{
//compare = getElement(counter).toString().compareToIgnoreCase(element.toString());
compare = current.toString().compareToIgnoreCase(element.toString());
//for display purposes
System.out.println(current.toString() + " compared to " + element.toString() + " is " + current.toString().compareToIgnoreCase(element.toString()));
if(compare > 0) { //want to add element into list if compare is negative. Won't necessarily be -1
iterator.previous(); //will need to move back a spot before adding. Otherwise will always add element after first encountered element that doesn't come before element inserting
iterator.add(element);
break; //make sure to break. No need to continue iterating
}
else
{
current = iterator.next();
//counter++;
}
}
//if element is larger than all existing elements in list
if(!myList.contains(element)) {
iterator.add(element);
}
}
}
public static void printList(ArrayList<AnyObject> myList) {
System.out.println("List contents:");
for(AnyObject element : myList) {
System.out.println(element.toString());
}
System.out.println();
}
}
I removed the counter int because you mentioned in your instructions that you don't have the option to use an index, so there's really no point in including it. It's also worth noting that compareTo and compareToIgnoreCase don't necessarily return -1 and 1. It can return any positive and negative values, so changing your conditions would be smart. Also, compareTo returns a negative number if value that's calling the method is less than the value that it's being compared to, so you want to stop iterating and add the value when compare is negative. Also, since you don't have iterator that's 1 element ahead of the position you're currently at in your list, you need to move the iterator back 1 element when compare returns a negative integer. If you don't, your new element will always be added immediately AFTER the first element that comes after it alphabetically. This is because you can't see the next element immediately after the iterator. Does this make sense?
For instance, if you have a list of 1, 2, 4, 5, and you want to add 3 to it, you would compare 1 to 3, 2 to 3, then 4 to 3. When your iterator reaches 2, it doesn't know what the next value is. Since 3 is larger than 2, it moves on to 4. 4 is less than 3, so add(3) gets called. However, this places 3 after the element it's being compared to (4). Your list would then be 1, 2, 4, 3, 5. The easiest way to fix this is to call iterator.previous(); immediately before iterator.add(3);
Let me know if you'd like further clarification.

How to check if a value in an Array is contained in the same array as its following one

In my Java program I have a String array of String arrays containing 3 values each.
String[][] actions =
{
new String[]{"R", "R'", "R2"},
new String[]{"L", "L'", "L2"},
new String[]{"D", "D'", "D2"},
new String[]{"U", "U'", "U2"},
new String[]{"F", "F'", "F2"},
new String[]{"B", "B'", "B2"}
};
Now I'm letting a randomizer pick 25 values out of these arrays by random and saving the results in a normal String array (let's call it results). Now I want to check if value 0 in results is contained in the same Array as value 1, meaning if value 0 is "U" and value 1 is "U'" it should re-roll the randomizer for value 1, ignoring the array value 0 is in. In the end I'd like to have an array of Strings where no String is in the same array as its following one.
Based on your comment, you might be looking for something like this?
public void mainMethod() {
...
for(int i=0; i<(results.length-1); i++) {
compare(results, i);
}
}
private void compare(String[] results, int index) {
// compare if both values are in the same array
if(getRowIndex(results[index]) == getRowIndex(results[index+1])) {
reRoll(results, (index+1)); // reroll if so
compare(results, index); // revalidate in case it re-rolls to the same array value
}
}
private void reRoll(String[] results, int index) {
//TODO
}
private void getRowIndex(...) {
//TODO
}
The final two methods are up to how you want to implement it. There are many ways...

How to compute smallest string in ArrayList using Comparator?

I need to write a static method in a class MinTester that computes the "smallest" string
from an ArrayList collection using a comparator object:
public static String min(ArrayList<String> list, Comparator<String> comp)
I cannot use the Collections class to compute the minimum.
Here is what I have so far.
public class MinTester
{
static String least;//This is static because it is being used in a static static context
public static String min(ArrayList<String> list, Comparator<String> comp)
{
int min = 0;
for( int i = 0; i < list.size(); i++ )
{
min = list.get(i).compareTo(list.get(i++));
if(min < 0)
{
least = list.get(i);
}
else if(min == 0)
{
least = list.get(i);
}
else
{
least = list.get(i++);
}
}
return least;
}
}
I am using the min value because I read that the compareTo method returns negative, 0, or positive whether the first string is less than, equal to, or greater than the second.
I am not getting any errors here from the method, So I try to test it in Main with this.
I get this warning: "Accessing static method min"
public static void main(String[] args)
{
// TODO code application logic here
MinTester s = new MinTester();
Comparator<String> comp = null;
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("ab");
list.add("abc");
list.add("abcd");
String a = s.min(list,comp);//Warning: Accessing static method min
System.out.println(a);
}
My output from a = "abcd". Can anyone help me figure out why I am getting "abcd" as the 'Min' string in the list? I am thinking that my error is coming from my min() method, but I am not sure where inside it or why.
If you need to find the shortest String in an ArrayList without sorting it, you can simply traverse the list and check the .length attribute of every String, always keeping track of the shortest one.
String shortest = list.get(0);
for(String str : list) {
if (str.length() < shortest.length()) {
shortest = str;
}
}
System.out.println("The shortest string: " + shortest);
EDIT :
You would use Comparator if you wanted to implement custom comparison of two strings. Comparing their length can be done in 1 line, so Comparator is really not necessary. If you absolutely need to use the Comparator, you would replace
if (str.length() < shortest.length())
by
if (comp.compare(str, shortest) < 0))
it's basically the same thing, except that you don't define the comparison by yourself but leave it up to the Comparator to decide, which String of the two is smaller. This way, if you wanted the way how the strings are compared in the future, you wouldn't have to rewrite the method, you would only supply a different Comparator.
Using Streams and Comparator-
Comparator<String> comparator = (str1, str2) -> str1.length() > str2.length() ? 1 : -1;
String smallest = Arrays.stream(input)
.sorted(comparator).findFirst().get();
Reference: Find Shortest Length String
you can just use string lengths to compare and use min method of stream:
stringSet.stream().min(Comparator.comparingInt(String::length)).get();
Some pointer, using the Comparator, to get the idea. I'm not going to solve the whole problem, as this is obviously your homework (implement the Comparator for the String lengths, understand what Comparator#compareTo(T, T) returns, read the Comparator API):
public static String min(List<String> list, Comparator<String> comp) {
String shortest = null;
for (String current : list) {
if (shortest == null) { // first iteration
shortest = current;
continue;
}
int comparisonResult = comp.compare(shortest, current);
// TODO: your task; update shortest, depending on comparisonResult
}
return shortest;
}
Don't want to do all of the work for you, so I will provide a solution in Scala:
object MinTest{
def main(args: Array[String]){
val list: util.List[String] = List("a", "ab", "abc", "abcd")
val m: String = min(list, (s1, s2) => s1.length - s2.length)
println(m) //output is: a
}
def min(list: util.List[String], comp: (String, String) => Int): String = {
if(list.isEmpty)
return null
var min = list(0)
for(i <- 0 until list.size if comp(list(i), min) < 0)
min = list(i)
min
}
}
Although this is a different language, the logic is still present. It's just your responsibility to convert it to Java.
This is simple guys, cant you just create a hashmap from a list where the number in the hashmap is the length of the string then the value in the hashmap is the string that goes with that value...
Sort by the key, select item zero, then you have it , right?
What I'm saying is put all the strings in a list.. for each loop on that list, while doing so note the string in one column and the length of that string in the other "while you're there" , sort by the length, then pick the first string that goes with that length.
You can get the length of the string element using the length method
e.g. list.get(0).length()
This should return the size of the string
Good Luck

Questions about implementing my own HashMap in Java

I am working on an assignment where I have to implement my own HashMap. In the assignment text it is being described as an Array of Lists, and whenever you want to add an element the place it ends up in the Array is determined by its hashCode. In my case it is positions from a spreadsheet, so I have just taken columnNumber + rowNumber and then converted that to a String and then to an int, as the hashCode, and then I insert it that place in the Array. It is of course inserted in the form of a Node(key, value), where the key is the position of the cell and the value is the value of the cell.
But I must say I do not understand why we need an Array of Lists, because if we then end up with a list with more than one element, will it not increase the look up time quite considerably? So should it not rather be an Array of Nodes?
Also I have found this implementation of a HashMap in Java:
public class HashEntry {
private int key;
private int value;
HashEntry(int key, int value) {
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
}
public class HashMap {
private final static int TABLE_SIZE = 128;
HashEntry[] table;
HashMap() {
table = new HashEntry[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = null;
}
public int get(int key) {
int hash = (key % TABLE_SIZE);
while (table[hash] != null && table[hash].getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == null)
return -1;
else
return table[hash].getValue();
}
public void put(int key, int value) {
int hash = (key % TABLE_SIZE);
while (table[hash] != null && table[hash].getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
table[hash] = new HashEntry(key, value);
}
}
So is it correct that the put method, looks first at the table[hash], and if that is not empty and if what is in there has not got the key, being inputted in the method put, then it moves on to table[(hash + 1) % TABLE_SIZE]. But if it is the same key it simply overwrites the value. So is that correctly understood? And is it because the get and put method use the same method of looking up the place in the Array, that given the same key they would end up at the same place in the Array?
I know these questions might be a bit basic, but I have spend quite some time trying to get this sorted out, why any help would be much appreciated!
Edit
So now I have tried implementing the HashMap myself via a Node class, which just
constructs a node with a key and a corresponding value, it has also got a getHashCode method, where I just concatenate the two values on each other.
I have also constructed a SinglyLinkedList (part of a previous assignment), which I use as the bucket.
And my Hash function is simply hashCode % hashMap.length.
Here is my own implementation, so what do you think of it?
package spreadsheet;
public class HashTableMap {
private SinglyLinkedListMap[] hashArray;
private int size;
public HashTableMap() {
hashArray = new SinglyLinkedListMap[64];
size = 0;
}
public void insert(final Position key, final Expression value) {
Node node = new Node(key, value);
int hashNumber = node.getHashCode() % hashArray.length;
SinglyLinkedListMap bucket = new SinglyLinkedListMap();
bucket.insert(key, value);
if(hashArray[hashNumber] == null) {
hashArray[hashNumber] = bucket;
size++;
}
if(hashArray[hashNumber] != null) {
SinglyLinkedListMap bucket2 = hashArray[hashNumber];
bucket2.insert(key, value);
hashArray[hashNumber] = bucket2;
size++;
}
if (hashArray.length == size) {
SinglyLinkedListMap[] newhashArray = new SinglyLinkedListMap[size * 2];
for (int i = 0; i < size; i++) {
newhashArray[i] = hashArray[i];
}
hashArray = newhashArray;
}
}
public Expression lookUp(final Position key) {
Node node = new Node(key, null);
int hashNumber = node.getHashCode() % hashArray.length;
SinglyLinkedListMap foundBucket = hashArray[hashNumber];
return foundBucket.lookUp(key);
}
}
The look up time should be around O(1), so I would like to know if that is the case? And if not how can I improve it, in that regard?
You have to have some plan to deal with hash collisions, in which two distinct keys fall in the same bucket, the same element of your array.
One of the simplest solutions is to keep a list of entries for each bucket.
If you have a good hashing algorithm, and make sure the number of buckets is bigger than the number of elements, you should end up with most buckets having zero or one items, so the list search should not take long. If the lists are getting too long it is time to rehash with more buckets to spread the data out.
It really depends on how good your hashcode method is. Lets say you tried to make it as bad as possible: You made hashcode return 1 every time. If that were the case, you'd have an array of lists, but only 1 element of the array would have any data in it. That element would just grow to have a huge list in it.
If you did that, you'd have a really inefficient hashmap. But, if your hashcode were a little better, it'd distribute the objects into many different array elements and as a result it'd be much more efficient.
The most ideal case (which often isn't achievable) is to have a hashcode method that returns a unique number no matter what object you put into it. If you could do that, you wouldn't ever need an array of lists. You could just use an array. But since your hashcode isn't "perfect" it's possible for two different objects to have the same hashcode. You need to be able to handle that scenario by putting them in a list at the same array element.
But, if your hashcode method was "pretty good" and rarely had collisions, you rarely would have more than 1 element in the list.
The Lists are often referred to as buckets and are a way of dealing with collisions. When two data elements have the same hash code mod TABLE SIZE they collide, but both must be stored.
A worse kind of collision is two different data point having the same key -- this is disallowed in hash tables and one will overwrite the others. If you just add row to column, then (2,1) and (1,2) will both have a key of 3, which means they cannot be stored in the same hash table. If you concatenated the strings together without a separator then the problem is with (12,1) versus (1, 21) --- both have key "121" With a separator (such as a comma) all the keys will be distinct.
Distinct keys can land in the same buck if there hashcodes are the same mod TABLE_SIZE. Those lists are one way to store the two values in the same bucket.
class SpreadSheetPosition {
int column;
int row;
#Override
public int hashCode() {
return column + row;
}
}
class HashMap {
private Liat[] buckets = new List[N];
public void put(Object key, Object value) {
int keyHashCode = key.hashCode();
int bucketIndex = keyHashCode % N;
...
}
}
Compare having N lists, with having just one list/array. For searching in a list one has to traverse possibly the entire list. By using an array of lists, one at least reduces the single lists. Possibly even getting a list of one or zero elements (null).
If the hashCode() is as unique as possible the chance for an immediate found is high.

How do I make this combinations/permutations method recursive?

I have an arraylist of Strings that want to have all possible combinations stored into another collection.
For example:
[air,bus,car]
->
[air]
[bus]
[car]
[air,bus]
[air,car]
[bus,air]
[bus,car]
[car,air]
[car,bus]
[air,bus,car]
[air,car,bus]
...
[car,bus,air]
Repetitions are not important. The code right now I have is:
public ArrayList<String> comb(ArrayList<String> wrds, ArrayList<String> str, int size)
{
ArrayList<String> s = new ArrayList<String>();
s.addAll(str);
if(size != a1.size())
{
Iterator e = a1.iterator();
while(e.hasNext())
{
s.add((String)e.next());
}
size++;
}
}
I am trying to get it to recursively call itself so it can store the combinations. Can I get any help as to where or which part I am missing in my code?
Seeing as this is homework, I'll try to give you background to the answer.
The key to solving this is to use recursion.
First imagine you have two items in your array. You'd could remove the first item to give you your first combination. Adding the remaining item to the first item gives you the second combination. Removing the second item give you the third combination. Adding the remaining item gives you the forth combination. If you had ["air", "bus"] it'd be something like:
["air"]
["air", "bus"]
["bus"]
["bus", "air"]
A method that returns that might look like:
String[][] combinations(String[] strings)
The important things to note are the an array containing a single string can be passed to this method and it can return an array containing an array with a single string in it.
The problem is complicated a little because you have to keep a tally of the string combinations, so before we get to solving that, it's important that you understand recursion.
Imagine you wanted to write a multiplication method that takes two numbers and multiplies them but you only have addition and subtraction at your disposal. You could write a recursive function that adds one of the numbers to itself until the other number reaches an exit condition, something like:
public int multiply(int value1, int value2)
{
if (value1 > 1)
{
int remaining = value1 - 1;
return value2 + multiply(remaining, value2);
}
else
{
return value2;
}
}
You can do just the same thing with an array, only instead to exiting when the a value hit's 1 you exit when the array contains one item, something like:
public String[][] combinations(String[] strings)
{
if (strings.length > 1)
{
...
}
else
{
return new String[][]{strings};
}
}
For reasons with the Java API it's much easier to use java.util.List rather than arrays so you want something like:
public List<List<String>> combinations(List<String> strings)
{
if (strings.size()> 1)
{
...
}
else
{
List<List<String>> result = new ArrayList<List<String>>();
result.add(strings);
return result;
}
}
Now it's the ... that's the important bit. You need to keep an list-of-lists that will be the result and iterate over the strings. For each of the strings you can add that string to the results and then you need create a sub-list that is minus the current string, which you use to call the combinations method again iterating over the result adding the current string each list it contains. In code it looks something like:
public List<List<String>> combinations(List<String> strings)
{
if (strings.size() > 1)
{
List<List<String>> result = new ArrayList<List<String>>();
for (String str : strings)
{
List<String> subStrings = new ArrayList<String>(strings);
subStrings.remove(str);
result.add(new ArrayList<String>(Arrays.asList(str)));
for (List<String> combinations : combinations(subStrings))
{
combinations.add(str);
result.add(combinations);
}
}
return result;
}
else
{
List<List<String>> result = new ArrayList<List<String>>();
result.add(new ArrayList<String>(strings));
return result;
}
}
In summary, what you're doing is reducing the list of strings down to a single item, then combining it with the preceeding items to produce all the possible combinations as the thread returns up the call stack.
public static void combination(Object[] array){
for(int x = 0; x < (1 << array.length); x++){
System.out.print("[");
for(int y = 0; y < array.length; y++){
if(checkIsOn(x, y){
System.out.print(array[y]);
}
}
System.out.println("]");
}
}
public static boolean checkIsOn(int mast, int position){
return (mast & (1 << position) > 0);
}
Use the list as a parameter to the recursive function. You can call the function from within itself with a new list containing everything except the first item.

Categories