I am building a data structure to learn more about java. I understand this program might be useless.
Here's what I want. I want to create a data structure that store smallest 3 values. if value is high, then ignore it. When storing values than I also want to put them in correct place so I don't have to sort them later. I can enter values by calling the add method.
so let's say I want to add 20, 10, 40, 30 than the result will be [10,20,30]. note I can only hold 3 smallest values and it store them as I place them.
I also understand that there are a lot of better ways for doing this but again this is just for learning purposes.
Question: I need help creating add method. I wrote some code but I am getting stuck with add method. Please help.
My Thinking: we might have to use a Iterator in add method?
public class MyJavaApp {
public static void main(String[] args){
MyClass<Integer> m = new MyClass<Integer>(3);
m.add(10);
m.add(20);
m.add(30);
m.add(40);
}
}
public class MyClass<V extends Comparable<V>> {
private V v[];
public MyClass(int s){
this.v = (V[])new Object[s];
}
public void add(V a){
}
}
Here is a rough sketch of the add method you have to implement.
You have to use the appropriate implementation of the compareTo method when comparing elements.
public void add(V a){
V temp = null;
if(a.compareTo( v[0]) == -1 ){
/*
keeping the v[0] in a temp variable since, v[0] could be the second
smallest value or the third smallest value.
Therefore call add method again to assign it to the correct
position.
*/
temp = v[0];
v[0] = a;
add(temp);
}else if(a.compareTo(v[0]) == 1 && a.compareTo(v[1]) == -1){
temp = v[1];
v[1] = a;
add(temp);
}else if(a.compareTo(v[1]) == 1 && a.compareTo(v[2]) == -1){
temp = v[2];
v[2] = a;
add(temp);
}
}
Therefore the v array will contain the lowerest elements.
Hope this helps.
A naive, inefficient approach would be (as you suggest) to iterate through the values and add / remove based on what you find:
public void add(Integer a)
{
// If fewer than 3 elements in the list, add and we're done.
if (m.size() < 3)
{
m.add(a);
return;
}
// If there's 3 elements, find the maximum.
int max = Integer.MIN_VALUE;
int index = -1;
for (int i=0; i<3; i++) {
int v = m.get(i);
if (v > max) {
max = v;
index = i;
}
}
// If a is less than the max, we need to add it and remove the existing max.
if (a < max) {
m.remove(index);
m.add(a);
}
}
Note: this has been written for Integer, not a generic type V. You'll need to generalise. It also doesn't keep the list sorted - another of your requirements.
Here's an implementation of that algorithm. It consists of looking for the right place to insert. Then it can be optimized for your requirements:
Don't bother looking past the size you want
Don't add more items than necessary
Here's the code. I added the toString() method for convenience. Only the add() method is interesting. Also this implementation is a bit more flexible as it respects the size you give to the constructor and doesn't assume 3.
I used a List rather than an array because it makes dealing with generics a lot easier. You'll find that using an array of generics makes using your class a bit more ugly (i.e. you have to deal with type erasure by providing a Class<V>).
import java.util.*;
public class MyClass<V extends Comparable<V>> {
private int s;
private List<V> v;
public MyClass(int s) {
this.s = s;
this.v = new ArrayList<V>(s);
}
public void add(V a) {
int i=0;
int l = v.size();
// Find the right index
while(i<l && v.get(i).compareTo(a) < 0) i++;
if(i<s) {
v.add(i, a);
// Truncate the list to make sure we don't store more values than needed
if(v.size() > s) v.remove(v.size()-1);
}
}
public String toString() {
StringBuilder result = new StringBuilder();
for(V item : v) {
result.append(item).append(',');
}
return result.toString();
}
}
Related
I have a class called Word in which each instance has String, ArrayList<Character>, and a double. Let's say there are 3 instances of this class. I would like to create a new ArrayList<String> in which all 3 word strings are contained. However, the order of the Strings must go from high to low of the doubles from their original instances. The major stipulation of this project is that the Collections.sort method cannot be used. Please see the code below and let me know if you can think of a way to write this loop (a loop is needed because there is actually +50,000 words):
import java.awt.List;
import java.util.ArrayList;
import java.util.Arrays;
public class WordRecommender {
String fileName;
public WordRecommender(String fileName) {
this.fileName = fileName;
}
public static void main(String[] args) {
ArrayList<Word> objectArray = new ArrayList<Word>();
objectArray.add(new Word("people", null ,0.8));
objectArray.add(new Word("dogs", null ,0.4));
objectArray.add(new Word("cats", null ,0.6));
ArrayList<String> outputArray = new ArrayList<String>();
for (int i = 0; i < finalArray.size(); i++) {
// code here to find the value of each double and place the
// associated strings into output Array from highest to lowest
}
// ideal outputArray order = ["people", "cats", "dogs"]
}
import java.util.ArrayList;
public class Word {
String wordName;
ArrayList<Character> uniqueLetters;
double percent;
public Word(String string, double percent) {
ArrayList<Character> tempArray = new ArrayList<Character>();
for (int i = 0; i < string.length(); i++) {
tempArray.add(string.charAt(i));
}
this.wordName = string;
this.uniqueLetters = tempArray;
this.percent = percent;
}
}
The result you need to achieve can be broken in 2 major steps:
Describing how, giving 2 Words, which of them will be put before the other in the List
Using the comparing method to actually sort your list of Words.
Step 1: How can we decide which word comes first?
Java has an interface called Comparable. The name is pretty self-explanatory. When you implement this interface in your Word class, you are telling Java that instances of this class can be compared against each other.
public class Word implements Comparable<Word>{
When you edit this line in your Word class, your IDE will probably complain about a "missing compareTo() method". The compareTo() method is defined in the Comparable interface and its job is deciding, from 2 instances, which one should be considered "larger" (or in our case, should be put first in the List).
An example of a usage is: "apple".compareTo("banana");. This method call should return a positive number if the first instance ("apple") is "larger", a negative number if the second instance ("banana") is "larger", or zero if both are of the same "value". By the way, the compareTo() method implemented by Strings in Java evaluates instances by alphabetical order.
So let's implement our version of the compareTo() method for our Word class.
#Override
public int compareTo(Word anotherWord) {
if(this.percent > anotherWord.percent) {
return 1;
} else if (this.percent < anotherWord.percent) {
return -1;
} else {
return 0;
}
}
Keep in mind that this implementation returns a positive value if the first instance is greater than the second, and a negative value in the other way around.
Now that we have a way of comparing our Words, we can move on to the sorting part.
Step 2: Sorting algorithms
There are a huge variety of sorting algorithms available on the internet. Some are less efficient, some are easier to implement. You can research some of them here.
For me, the easiest sorting algorithm is called BubbleSort. It is not very efficient, though.
ArrayList<Word> objectArray = new ArrayList<Word>();
objectArray.add(new Word("people", 0.8));
objectArray.add(new Word("dogs", 0.4));
objectArray.add(new Word("cats", 0.6));
for(int i = 0; i < objectArray.size() - 1; i++) {
for(int j = 0; j < objectArray.size() - i - 1; j++) {
// Remember: a compareTo() call returning a negative number
// means that the first instance is smaller than the second.
if(objectArray.get(j).compareTo(objectArray.get(j + 1)) < 0) {
Word auxiliary = objectArray.get(j);
objectArray.set(j, objectArray.get(j + 1));
objectArray.set(j + 1, auxiliary);
}
}
}
These two nested for loops will sort objectArray in descending order of percent.
I implemented a solution that involves a sorting algorithm and usage of java.util.Comparable both.
First, you need to implement Word class with java.util.Comparable so that you can define how to compare Word class in order to determine which one is greater or lower than the other. In this case, it will be the percent field.
public class Word implements Comparable<Word> {
String wordName;
ArrayList<Character> uniqueLetters;
double percent;
public Word(String string, double percent) {
ArrayList<Character> tempArray = new ArrayList<Character>();
for (int i = 0; i < string.length(); i++) {
tempArray.add(string.charAt(i));
}
this.wordName = string;
this.uniqueLetters = tempArray;
this.percent = percent;
}
#Override
public int compareTo(Word o) {
// It is better to delegate to built-in Double compare
// because all we need to compare doubles
return Double.compare(this.percent, o.percent);
}
#Override
public String toString() {
return this.wordName;
}
}
Second, the most important part is to implement a sorting algorithm. It can be challenging to implement them on your own so I suggest study them first.
For my solution it will be a regular implementation of Quick Sort algorithm as follows:
public class QuickSort {
private Word[] array;
public QuickSort(Word... words) {
this.array = words;
}
public Word[] sort(){
this.sort(this.array, 0, this.array.length-1);
return this.array;
}
private void sort(Word[] array, int begin, int end) {
//exit condition
if (begin >= end)
return;
Word pivot = array[end];
int sortIndex = begin;
for (int i = begin; i < end; i++) {
// instead of > we use compareTo to externalize comparison logic
// greater than (>) means we sort in descending order
if (array[i].compareTo(pivot) > 0) {
Word swap = array[sortIndex];
array[sortIndex] = array[i];
array[i] = swap;
sortIndex++;
}
}
//placing pivot to the sort index
Word swap = array[sortIndex];
array[sortIndex] = pivot;
array[end] = swap;
this.sort(array, begin, sortIndex-1);
this.sort(array, sortIndex+1, end);
}
}
Finally, you just use QuickSort helper class to sort your collection of Word and get the sorted output:
public class WordRecommender {
String fileName;
public WordRecommender(String fileName) {
this.fileName = fileName;
}
public static void main(String[] args) {
ArrayList<Word> objectArray = new ArrayList<Word>();
objectArray.add(new Word("people" ,0.8));
objectArray.add(new Word("dogs", 0.4));
objectArray.add(new Word("cats" ,0.6));
QuickSort quickSort = new QuickSort(objectArray.toArray(new Word[]{}));
Word[] sortedWordArray = quickSort.sort();
//output: [people, cats, dogs]
System.out.println(Arrays.asList(sortedWordArray));
}
}
I have a set of sets of integers: Set<Set<Integer>>.
I need to add integers to the set of sets as if it were a double array. So add(2,3) would have to add integer 3 to the 2nd set.
I know a set is not very suitable for this operation but it's not my call.
The commented line below clearly does not work but it shows the intention.
My question is how to add an integer to a set while iterating?
If it's necessary to identify each set, how would one do this?
#Override
public void add(int a, int b) {
if (!isValidPair(a, b)) {
throw new IllegalStateException("!isValidPair does not hold for (a,b)");
}
Iterator<Set<Integer>> it = relation.iterator();
int i = 0;
while (it.hasNext() && i <= a) {
//it.next().add(b);
i++;
}
}
One fundamental things you should be aware of, for which makes all existing answer in this question not working:
Once an object is added in a Set (similarly, as key in Map), it is not supposed to change (at least not in aspects that will change its equals() and hashCode()). The "Uniqueness" checking is done only when you add the object into the Set.
For example
Set<Set<Integer>> bigSet = new HashSet<>();
Set<Integer> v1 = new HashSet<>(Arrays.asList(1,2));
bigSet.add(v1);
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2)))); // True
v1.add(3);
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2)))); // False!!
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2,3)))); // False!!
You can see how the set is corrupted. It contains a [1,2,3] but contains() does not work, neither for [1,2] nor [1,2,3].
Another fundamental thing is, your so-called '2nd set' may not make sense. Set implementation like HashSet maintain the values in arbitrary order.
So, with these in mind, what you may do is:
First find the n-th value, and remove it
add the value into the removed value set
re-add the value set.
Something like this (pseudo code again):
int i = 0;
Set<Integer> setToAdd = null;
for (Iterator itr = bigSet.iterator; itr.hasNext(); ++i) {
Set<Integer> s = itr.next();
if (i == inputIndex) {
// remove the set first
itr.remove();
setToAdd = s;
break;
}
}
// update the set and re-add it back
if (setToAdd != null) {
setToAdd.add(inputNumber);
bigSet.add(setToAdd);
}
Use a for-each loop and make your life easier.
public boolean add(int index, int value) {
// because a and b suck as variable names
if (index < 0 || index >= values.size()) {
return false;
}
int iter = 0;
for (Set<Integer> values : relation) {
if (iter++ == index) {
return values.add(value):
}
}
return false;
}
Now all you have to figure out is what to do if relation is unordered, as a Set or a relation are, because in that case a different Set<Integer> could match the same index each time the loop executes.
Use can use Iterators of Guava library like this :
#Override
public void add(int a, int b) {
if (!isValidPair(a, b)) {
throw new IllegalStateException("!isValidPair does not hold for (a,b)");
}
Iterators.get(relation.iterator(), a).add(b);
}
Edit : without Guava:
Iterator<Set<Integer>> iterator = relation.iterator();
for(int i = 0; i < a && iterator.hasNext(); ++i) {
iterator.next();
}
if(iterator.hasNext()) {
iterator.next().add(b);
}
This is my situation: I have list A of values. I also have list B which contains a hierarchy of ranks. The first being of the highest, last being of the lowest. List A will contain one, some, or all of the values from list B. I want to see which value from list A is of the highest degree (or lowest index) on list B. How would I do this best?
Just in case its still unclear, this is an example:
List A: Merchant, Peasant, Queen
List B: King, Queen, Knight, Merchant, Peasant
I'd want the method to spit out Queen in this case
Assuming List B is already sorted from Top Rank -> Bottom rank, one arbitary way you could solve it is with
public static void main (String[] args) throws Exception {
String[] firstList = { "Merchant", "Peasant", "Queen" };
String[] secondList = { "King", "Queen", "Knight", "Merchant", "Peasant" };
for (String highRank : secondList) {
for (String lowRank : firstList) {
if (highRank.equalsIgnoreCase(lowRank)) {
System.out.println(highRank);
return;
}
}
}
}
What you are describing is called a "partial ordering", and the proper way to implement the behavior you're looking for in Java is with a Comparator that defines the ordering; something like:
public class PartialOrdering<T> implements Comparator<T> {
private final Map<T, Integer> listPositions = new HashMap<>();
public PartialOrdering(List<T> elements) {
for (int i = 0; i < elements.size(); i++) {
listPositions.put(elements.get(i), i);
}
}
public int compare(T a, T b) {
Integer aPos = listPositions.get(a);
Integer bPos = listPositions.get(b);
if (aPos == null || bPos == null) {
throw new IllegalArgumentException(
"PartialOrdering can only compare elements it's aware of.");
}
return Integer.compare(aPos, bPos);
}
}
You can then simply call Collections.max() to find the largest value in your first list.
This is much more efficient than either of the other answers, which are both O(n^2) and don't handle unknown elements coherently (they assume we have a total ordering).
Even better than implementing your own PartialOrdering, however, is to use Guava's Ordering class, which provides an efficient partial ordering and a number of other useful tools. With Guava all you need to do is:
// Or store the result of Ordering.explicit() if you need to reuse it
Ordering.explicit(listB).max(listA);
I think this might work give it a Try:
function int getHighest(List<String> listA, List<String> listB)
{
int index = 0;
int max = 100;
int tmpMax = 0;
for(String test:lista)
{
for(int i =0;i<listb.size();++i)
{
if(list.get(i).equals(test))
{
tmpMax = index;
}
}
if(tmpMax < max) max = tmpMax;
++index;
}
return max;
}
I have an ArrayList in Java :
{"PatMic", "PatientDoc", "Phram", "Patnet", "PatientA"}
All the elements have a number assigned : PatMic = 20, PatientDoc = 30, Phram = 40, Patnet = 50, PatientA = 60.
And my current Comparator :
Comparator<String> comparator = new Comparator<String>() {
#Override
public int compare(final String o1, final String o2) {
final int numbr1 = getElementNumber(); //Returns element's number in a list
final int numbr2 = getElementNumber();
if (numbr1 > numbr2 ) {
return 1;
} else if (numbr1 < numbr2 ) {
return -1;
}
return 0;
}
};
Collections.sort(strings, comparator);
I do not want to change the assigned numbers to each element but would want to move the element PatientA in between PatMic and PatientDoc so the modified list should look like :
{"PatMic", "PatientA" "PatientDoc", "Phram", "Patnet"}
Could someone please suggest how to achieve this? I tried many ways to modify the existing Comparator logic but in vain. Thank you.
You are trying to sort based on some inherent value associated with a String. Therefore, sorting on a String itself is probably not correct. What you probably want to use is either a custom object (implement equals, hashCode and the interface Comparable), or an enum type. This will allow you to change the internal state of these objects explicitly, which will manifest itself naturally when using a Comparator. For example, using a class:
class MyClass implements Comparable
{
private String name;
private int value;
//Constructor
public MyClass(String s, int v)
{
name = s;
value = v;
}
//Getters and setters
//Implement comparing method
}
Then you can use these objects in place of your Strings:
//...
MyClass patMic = new MyClass("PatMic", 20);
// So on..
First, you should give you comparator sufficient knowledge about what it should do. I mean you should have some data available to comparator that says something like "okay, sort them all by associated number except this one - place it right here". "Right here" could be anything that points exact position, I gonna choose "before that element".
So here we go
public void sortWithException(List<String> data, final Map<String, Integer> numbers, final String element, final String next) {
Collections.sort(data, new Comparator<String>() {
#Override
public int compare(String first, String second) {
if (first.equals(element) || second.equals(element)) { //the exception
Integer nextNumber = numbers.get(next);
Integer firstNumber = numbers.get(first);
Integer secondNumber = numbers.get(second);
if (first.equals(element)) {
if (next == null) // placing the exception after ANY element
return 1;
return secondNumber >= nextNumber ? -1 : 1; //placing the element before next and after all next's predecessors
} else { // second.equals(element)
if (next == null)
return -1;
return firstNumber >= nextNumber ? 1 : -1;
}
} else { //normal sort
return numbers.get(first) - numbers.get(second);
}
}
});
}
and call it like sortWithException(data, numbers, "PatientA", "PatientDoc")
Note that i used Map for associated numbers, you should probably use your own method to get those numbers.
I have seen a number of questions dealing with finding the min index. There is a solution on this related question, that uses 2 built-in functions, min and then indexOf. The problem with that approach is that it goes over the whole list twice. Is there any single built-in function for minimum/maximum indices?
As of Java 7, there is no such method; you would have to implement it yourself. Keep in mind that for a List, there's not necessarily one correct answer to this question, as a single object can be added to a List multiple times, or you could have multiple equal objects.
Here's a general solution to that problem along with a short example.
It iterates the list exactly once and returns the index of the minimal item and the minimal item itself. It is implemented to return the first index and item, if the smallest item has one or more equal items in the list.
You can adjust the immutable ListMin<T> class to your needs and adapt the code to find the maxima.
public class ListMin<T> {
final int index;
final T item;
public ListMin(int index, T item) {
this.index = index;
this.item = item;
}
public static <E extends Comparable<E>> ListMin<E> getListMin(List<E> list) {
if (list.size() == 0) {
// throw exception, do what you want.
}
ListIterator<E> it = list.listIterator();
int minIndex = 0;
E minItem = it.next(); // first is minimum
while (it.hasNext()) {
E item = it.next();
if (item.compareTo(minItem) < 0) {
minItem = item;
minIndex = it.previousIndex();
}
}
return new ListMin<E>(minIndex, minItem);
}
public static void main(String[] args) {
List<String> list = Arrays.asList("B", "A", "C");
ListMin<String> listMin = getListMin(list);
System.out.println(listMin.index);
System.out.println(listMin.item);
}
}