Move an element up in the list using Comparator - java

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.

Related

How to check to see which value of a list is highest another another list

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;
}

creating java generic data structure

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();
}
}

Removing Duplicate Entries in Array - Java

For Java practice, I am trying to create a method inside my EmployeesDirectory Class that:
Removes Duplicate entries from the array
The array should be the same length after removing duplicates
Non-Empty entries should be making a contiguous sequence at the beginning of the array - and the actualNum should keep a record of the entries
Duplicate Means: Same Name, Position and Salary
Here is my Current Code:
I am unsure on how to implement this - any help would be appreciated
class EmployeeDirectory {
private Employee dir[];
private int size;
private int actualNum;
public EmployeeDirectory(int n) {
this.size = n;
dir = new Employee[size];
}
public boolean add(String name, String position, double salary) {
if (dir[size-1] != null) {
dir[actualNum] = new Employee(name, position, salary);
actualNum++;
return true;
} else {
return false;
}
}
}
I'd rather you did not write a distinct method for removing duplicates. If I were you, I would search for duplicates in add method and then instantly decide whether I need to add Employee.
Also, why don't you use Sets (link for HashSet) instead of arrays for your purpose? Sets by their own definition disallow adding duplicates, so they seem to be appropriate as a solution
First of all, Override equals and hashCode methods in Employee class as follow
#Override
public boolean equals(Object other) {
if(this == other) return true;
if(other == null || (this.getClass() != other.getClass())){
return false;
}
Employee guest = (Employee) other;
return Objects.equals(guest.name, name)
&& Objects.equals(guest.position, position)
&& Objects.equals(guest.salary, salary);
}
#Override
public int hashCode() {
return Arrays.hashCode(new Object[] {
name,
position,
salary
});
}
Then you can use Stream API distinct method to remove duplicates
Returns a stream consisting of the distinct elements (according to
Object.equals(Object)) of this stream.
You can do it like so
Employee e1 = new Employee("John", "developer", 2000);
Employee e2 = new Employee("John", "developer", 2000);
Employee e3 = new Employee("Fres", "designer", 1500);
Employee[] allEmployees = new Employee[100];
allEmployees[0] = e1;
allEmployees[1] = e2;
allEmployees[2] = e3;
allEmployees = Arrays.asList(allEmployees).stream().distinct()
.toArray(Employee[]::new);
Arrays.asList(allEmployees).forEach(System.out::println);
Output: (keeping both empty and non-empty entries)
John developer 2000.0
Fres designer 1500.0
null
Unfortunately, I have not got the Employee class to verify my code, but try this:
void removeDuplicates() {
int length = dir.length;
HashSet set = new HashSet(Arrays.asList(dir));
dir = new Employee[length];
Employee[] temp = (Employee[]) set.toArray();
for (int index = 0; index < temp.length; index++)
dir[index] = temp[index];
}
The code must remain the size of array after deletion the duplicates. At the beginning of array there must be valid Employees, at the end - nulls.
And don't forget to add this at the beginning of your .java file
import java.util.Arrays;
import java.util.HashSet;
If your task states as "remove duplicates from array" (i. e. you cannot use ArrayList or control when adding items), you can use the following approach:
public void removeDuplicates() {
Set<Employee> d = new HashSet<>(); // here to store distinct items
int shift = 0;
for (int i = 0; i > dir.length; i++) {
if (d.contains(dir[i])) { // duplicate, shift += 1
shift++;
} else { // distinct
d.add(dir[i]); // copy to `d` set
dir[i - shift] = dir[i]; // move item left
}
}
for (int i = d.size(); i < dir.length; i++)
dir[i] = null; // fill rest of array with nulls
actualNum = d.size();
}
Here, shift variable stores number of duplicates found in the array so far. Every distinct item is moved to shift positions left in order to make sequence continuous while keeping initial ordering. Then remaining items are altered to nulls.
To make hash-based collections work with Employee instances correctly, you also need to override hashCode() and equals() methods as follows:
public class Employee {
//...
#Override
public int hashCode() {
return Objects.hash(name, position, salary);
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!o.getType().equals(this.getType()) return false;
Employee e = (Employee) o;
return Objects.equals(e.name, name)
&& Objects.equals(e.position, position)
&& Objects.equals(e.salary, salary); // or e.salary == salary, if it primitive type
}
}

Working with multiple arrays and incrementing objects within them

Suppose I have these classes:
public class EdgeI {
public int from;
public int to;
public EdgeI (int a1, int a2) {
from = a1;
to = a2;
}
}
public class VertexI {
public List neighbors;
public String info;
public VertexI (List neig, String str) {
neighbors = neig;
info = str;
}
}
public class vertexWeight {
public int v;
public int w;
public vertexWeight (int vertexNum, int wum) {
v = vertexNum;
w = wum;
}
}
Suppose I have a list of EdgeI objects that contain pairs of numbers. Suppose I also have a list of VertexI objects that contain an empty list and a string. I want to add the following to the empty list:
Suppose I have this as my list of EdgeI objects
(1,2), (1,2) (1,2), (1,3), (1,3), (1,4)
For the first VertexI object in the list, I want to add the following list
(2,3) (3,2)
to the vertex object. Basically I want to take the "to" integer and the number of times that "to" integer repeats and create vertexWeight objects to add to the list of neig from the VertexI class. So neig for the first VertexI object would be the vertexWeight objects (2,3) and (3,2). To implement this I created this so far:
public void createGraph () {
int oldFrom = -1;
int oldTo = -1;
for(int i = 0; i < edges.size(); i++) {
EdgeI e = edges.get(i);
int from = e.from;
int to = e.to;
VertexI v = vertices.get(from);
v.neighbors.add(new vertexWeight (to, 1));
if (from == oldFrom && to == oldTo){}
//have to add increment the number 1 in the vertex weight object somehow
else {
oldFrom = from;
oldTo = to;
}
}
}
I need some tips or methods to go about implementing this? My logic may be incorrect, thats where I need the most help I think.
I/we are having to make some assumptions about what you want to do -- for instance, in your example, the 'to' values are small, simple integers, but we have no indication that all 'to' values are in that category.
I recommend creating a HashMap entry for each 'to' value; the index is either an Integer or a Float (or a double) that corresponds to your 'to' entry, and the value holds an int that you can increment each time that 'to' value is encountered.
If that doesn't solve your problem, perhaps you can explain more of what you need.

I can't figure out comparator

I'm trying to sort an arraylist but I can't wrap my head around the comparator. I don't understand how to define sortable fields from my arraylist which is created from a text file. Furthermore I'm unsure of the comparator logic. It seems to me like create a set of comparator functions, and then later invoke them. Is this true?
So far my code looks like this:
public class coord implements Comparator<Sort> {
private int index;
private int index2;
private double dista;
}
public class Sort {
List<Sort> coords = new ArrayList<Sort>();
public static void main(String[] args) throws Exception {
ArrayList dist = new ArrayList();
File file = new File("2.txt");
FileWriter writer = new FileWriter("2c.txt");
try {
Scanner scanner = new Scanner(file).useDelimiter("\\s+");
while (scanner.hasNextLine())
{
int index = scanner.nextInt();
int index2 = scanner.nextInt();
double dista = scanner.nextDouble();
System.out.println(index + " " + index2 + " " + dista);
}
}
}
public class EmpSort {
static final Comparator<coord> SENIORITY_ORDER =
new Comparator<coord>() {
public int compare(coord e1, coord e2) {
return e2.index().compareTo(e1.index());
}
};
static final Collection<coord> coords = ;
public static void main(String[] args) {
List<Sorted>e = new ArrayList<Sorted>(coords);
Collections.sort(e, SENIORITY_ORDER);
System.out.println(e);
I appreciate any help anyone can give.
Comparator logic is simple. When you sort an array of elements you have two choices - sort using the Comparable on each element (assuming there is one) or supply a Comparator. If your array contains complex elements or there are different sort criteria then the latter choice is probably what you need to use.
Each time the comparator is called you must say if element 1 is "less than" element 2 in which case return a negative number, element 1 is "greater than" element 3 in which case return a positive number. Otherwise if elements are equal return 0. You may also do reference and null comparison before comparing values so that null elements are logically "less than" non-null elements and so on.
If elements are "equal" then you may wish to sort by a secondary field and then a third field and keep going until the sort order is unambiguous.
A simple comparator for a class Complex which has fields a & b and we want to sort on a:
class Complex {
public String a = "";
public String b = "";
}
//...
Collections.sort(someList, new Comparator<Complex>() {
public int compare(Complex e1, Complex e2) {
if (e1 == e2) {
// Refs could be null or equal
return 0;
}
if (e1 == null && e2 != null) {
return -1;
}
if (e2 == null && e1 != null) {
return 1;
}
if (e1.a == e2.a) {
return 0;
}
if (e1.a == null && e2.a != null) {
return -1;
}
if (e1.a != null && e2.a == null) {
return 1;
}
// Just use the Comparable on the fields
return e1.a.compareTo(e2.a);
}
});

Categories