Sorting String differently on some conditional - java

I wondered how I could change ordering-direction only on some contitional. In my case Strings starting with 'BB' should be ordered in the other direction, everything else should be ordered as usual.
My Test-Class:
public class StringTest {
public static void main(String[] args) {
SomeClass someClass1= new SomeClass("AA");
SomeClass someClass2= new SomeClass("AB");
SomeClass someClass3= new SomeClass("CB4");
SomeClass someClass4= new SomeClass("BB7");
SomeClass someClass5= new SomeClass("BB9");
SomeClass someClass6= new SomeClass("BB3");
SomeClass someClass7= new SomeClass("CB3");
List<SomeClass> list = new ArrayList<SomeClass>();
list.add(someClass1);
list.add(someClass2);
list.add(someClass3);
list.add(someClass4);
list.add(someClass5);
list.add(someClass6);
list.add(someClass7);
Collections.sort(list);
for (SomeClass someClass : list) {
System.out.println(someClass.getSomeField());
}
}
}
My Comparator:
public class SomeClass implements Comparable<SomeClass>
{
private String someField;
public int compareTo(final SomeClass o)
{
int res = 0;
if (someField.startsWith("BB"))
{
res = o.someField.compareTo(someField);
}
else
{
res = someField.compareTo(o.someField);
}
return res;
}
}
My desired output:
AA
AB
BB9
BB7
BB3
CB3
CB4
The actual result so far:
AA
AB
CB3
BB9
BB7
BB3
CB4
Jonny

You need to make sure your Comparator applies the different sorting only when both elements start with "BB". Right now your Comparator applies the different sorting even if you compare "BB9" with "CB3" and therefore the latter is being sorted in front of BB9.
public class SomeClass implements Comparable<SomeClass>
{
private String someField;
public int compareTo(final SomeClass o)
{
int res = 0;
if (someField.startsWith("BB") && o.someField.startsWith("BB"))
{
res = o.someField.compareTo(someField);
}
else
{
res = someField.compareTo(o.someField);
}
return res;
}
}

if(someField.startsWith("BB") && o.someField.startsWith("BB")))
Try this change in your compareTo method which may solve your problem.

Related

How to sort classes according to their inheritance level

Please create an algorithm that takes a list of classes and sorts them in a way, that whenever
Class A is subclass of class B
Class A implements interface B
The index of B is smaller than A.
What I tried so far is,
public void sortClasses(Class... classes) {
List<Class> classesToSort = new ArrayList<>();
for(Class c : classes) {
Class superClass = c.getSuperclass();
if(superClass != null) {
classesToSort.add(superClass);
}
Class[] interfaces = c.getInterfaces();
if(interfaces.length > 0) {
classesToSort.addAll(Arrays.asList(interfaces));
}
classesToSort.add(c);
}
}
I'm not sure whether this works or not.
If you hear "sorting" in Java, always think "Comparator". If you have a Comparator which is able to compare two elements of a given type (in your case, Class), you can sort a list of those elements using Collections.sort(elements, comparator).
To write a Comparator, you need to implement its method
public int compare(E el1, E el2);
with E being the type of the elements, so in your case
public int compare(Class<?> c1, Class<?> c2);
because you're comparing Class objects. You need to return -1 if c1 < c2, or 1 if c2 < c2, or 0 if they're equal (for this comparison).
Now you have two requirements that will help you implement the comparison:
class A is subclass of class B
class A implements the interface B
Both of these can be checked by using the method Java provides in Class called isAssignableFrom.
c1.isAssignableFrom(c2)
is true if c1 "is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter" (ie c2) - so basically c1.isSuperclassOf(c2). For your comparison, that means, if it returns true, c1 < c2.
So let's use this to write the Comparator.
public HierarchyComparator implements Comparator<Class<?>> {
public int compare(Class<?> c1, Class<?> c2) {
int result;
// we need to do this check because isAssignableFrom is true in this case
// and we would get an order that doesn't exist
if (c1.equals(c2)) {
return 0;
}
if (c1.isAssignableFrom(c2)) {
return -1;
} else if (c2.isAssignableFrom(c1)) {
return 1;
}
// no hierarchy
return 0;
}
}
Then, you can sort classes by
public List<Class<?>> sort(Class<?>... classes) {
List<Class<?>> result = new ArrayList<>(Arrays.asList(classes));
Collections.sort(result, new HierarchyComparator());
}
Hope this helps. Class PrintClassHierarchy needs the input of classes which you want to print in hierarchy order.
//sample classes for tutorial
class A{
}
class B extends A {
}
class C extends A {
}
class D extends C {
}
class E extends B {
}
class F extends B {
}
//print hierarchy
public class PrintClassHierarchy {
private static final String PADDING = " ";
private static final String PADDING_WITH_COLUMN = " | ";
private static final String PADDING_WITH_ENTRY = " |--- ";
private static final String BASE_CLASS = Object.class.getName();
private final Map<String, List<String>> subClazzEntries = new HashMap<>();
public static void main(final String[] args) {
new PrintClassHierarchy(
A.class,
B.class,
C.class,
D.class,
E.class,
F.class
).printHierarchy();
}
public PrintClassHierarchy(final Class<?>... clazzes) {
// get all entries of tree
traverseClasses(clazzes);
}
public void printHierarchy() {
// print collected entries as ASCII tree
printHierarchy(BASE_CLASS, new Stack<Boolean>());
}
private void printHierarchy(final String clazzName, final Stack<Boolean> moreClassesInHierarchy) {
if (!moreClassesInHierarchy.empty()) {
for (final Boolean hasColumn : moreClassesInHierarchy.subList(0, moreClassesInHierarchy.size() - 1)) {
System.out.print(hasColumn.booleanValue() ? PADDING_WITH_COLUMN : PADDING);
}
}
if (!moreClassesInHierarchy.empty()) {
System.out.print(PADDING_WITH_ENTRY);
}
System.out.println(clazzName);
if (subClazzEntries.containsKey(clazzName)) {
final List<String> list = subClazzEntries.get(clazzName);
for (int i = 0; i < list.size(); i++) {
// if there is another class that comes beneath the next class, flag this level
moreClassesInHierarchy.push(new Boolean(i < list.size() - 1));
printHierarchy(list.get(i), moreClassesInHierarchy);
moreClassesInHierarchy.removeElementAt(moreClassesInHierarchy.size() - 1);
}
}
}
private void traverseClasses(final Class<?>... clazzes) {
// do the traverseClasses on each provided class (possible since Java 8)
Arrays.asList(clazzes).forEach(c -> traverseClasses(c, 0));
}
private void traverseClasses(final Class<?> clazz, final int level) {
final Class<?> superClazz = clazz.getSuperclass();
if (superClazz == null) {
// we arrived java.lang.Object
return;
}
final String name = clazz.getName();
final String superName = superClazz.getName();
if (subClazzEntries.containsKey(superName)) {
final List<String> list = subClazzEntries.get(superName);
if (!list.contains(name)) {
list.add(name);
Collections.sort(list); // SortedList
}
} else {
subClazzEntries.put(superName, new ArrayList<String>(Arrays.asList(name)));
}
traverseClasses(superClazz, level + 1);
}
}
OUTPUT:
java.lang.Object
|--- A
|--- B
| |--- E
| |--- F
|--- C
|--- D
You can do this using constructor.
List<String> listOfClasses = new ArrayList<>();
public class MyClass{
public MyClass(){
listOfClasses.add(this.getClass().getSimpleName());
}
}
public class SubClass extends MyClass{
public SubClass(){
// here, first statement super() which calls constructor of superclass
listOfClasses.add(this.getClass().getSimpleName());
}
}
So,when you create object in subclass, then constructor of all classes are called and these are stored in listOfClasses in sorted way.

Object Recursion and flatten the objects in a List

Looking for a best solution for the object recursion problem. Below is the example:
Class:
public class SomeObject {
private List<SomeObject> objects;
}
Data:
Input:
SomeObject has List of objects and every Object in list is of SomeObject Type and has list inside them. (Recursive in nature)
Requirement is to flatten them and put them in a single arraylist.
The flatten List should have all the SomeObject types.
Can anyone suggest what's the best way to handle this case. Thanks!
If you are not using Java 8, You might consider doing it this way.
import java.util.ArrayList;
import java.util.List;
public class TestClass {
static List<SomeObject> flatList = new ArrayList<SomeObject>();
public static void flatten(SomeObject object) {
if (object != null ){
if( object.getObjects() != null && !object.getObjects().isEmpty()) {
for (SomeObject o : object.getObjects()) {
flatten(o);
flatList.add(object);
}
}
}
}
public static void main(String[] args) {
SomeObject o1 = new SomeObject("1");
SomeObject o2 = new SomeObject("2");
SomeObject o3 = new SomeObject("3");
SomeObject o4 = new SomeObject("4");
o1.addObject(o2);
o2.addObject(o3);
o3.addObject(o4);
flatten(o1);
for (SomeObject obj : flatList){
System.out.println(obj.getObjectName());
}
}
}
class SomeObject {
String objectName = "";
public SomeObject(String name) {
this.objectName = name;
}
private List<SomeObject> objects = new ArrayList<SomeObject>();
public List<SomeObject> getObjects() {
return objects;
}
public void setObjects(List<SomeObject> objects) {
this.objects = objects;
}
public void addObject(SomeObject o){
objects.add(o);
}
public String getObjectName() {
return objectName;
}
}
To make recursion, the method for a given object would require to :
add itself : add to list
ask its children to do same : collect all children getAllChildren()
public class Foo {
private String s;
private List<Foo> fooList = new ArrayList<>();
public Foo(String a) {
s = a;
}
public static void main(String[] args) {
Foo a = new Foo("a");
Foo b = new Foo("b");
Foo c = new Foo("c");
Foo d = new Foo("d");
Foo e = new Foo("e");
a.fooList.add(b);
b.fooList.add(c);
c.fooList.add(e);
a.fooList.add(d);
List<Foo> list = a.getAllChildren();
System.out.println(list);
}
private List<Foo> getAllChildren() {
List<Foo> l = fooList.stream().flatMap(elt -> elt.getAllChildren().stream())
.collect(Collectors.toList());
l.add(this);
return l;
}
#Override
public String toString() { return s; }
}
Input Structure :
a-b-c-d
\ \
e f
Output List :
[d, f, c, b, e, a]

Filtering an ArrayList<MyClass> on the basis of a MyClass.MyString and summing up a MyClass.MyCount

I've a Bean Class MyClass as
public class MyClass {
String myString;
int myCount;
public MyClass() {
}
public MyClass(String myString, int myCount) {
super();
this.myString = myString;
this.myCount = myCount;
}
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
public int getMyCount() {
return myCount;
}
public void setMyCount(int myCount) {
this.myCount = myCount;
}}
I have an ArrayList as
MyClass obj1 = new MyClass("1-ABC_2-PQR_1-PQR_1-DEF", 4);
MyClass obj2 = new MyClass("1-ABC_2-PQR_3-XYZ_1-PQR_1-DEF", 12);
MyClass obj3 = new MyClass("1-ABC_1-PQR_1-DEF", 3);
MyClass obj4 = new MyClass("3-ABC_2-PQR_1-DEF", 3);
ArrayList<MyClass> rawList = new ArrayList<MyClass>();
rawList.add(obj1); rawList.add(obj2); rawList.add(obj3); rawList.add(obj4);
For the whole ArrayList I am picking out the MyClass.myString iteratively and based on a selection criteria tailoring them and setting them back to their respective objects. After this, I need to create a New ArrayList in which if myString for one object matches that of the other then I need to add the MyClass.myCount for them both and delete of one of the objects.
For example, in the values I've taken, if after tailoring obj1.getMyString() matches obj3.getMyString() as 1-ABC_1-PQR_1-DEF then I need to add obj1.getMyCount() and obj3.getMyCount() and save only one of them in the new ArrayList.
I am doing this in the following way, but I am hoping to get a efficient and fail proof way to do this.
int j = 0;
if (rawList.size() > 0)
list.add(rawList.get(0));
for (int i = 1; i < rawList.size(); i++) {
if (rawList.get(i).getMyString()
.equals(list.get(j).getMyString())) {
list.get(j).setMyCount(
list.get(j).getMyCount()
+ rawList.get(i)
.getMyCount());
} else {
j++;
list.add(rawList.get(i));
}
}
I guess you could use a map:
Map<String,MyClass> map = new LinkedHashMap<>();
for (MyClass obj: rawList) {
MyClass other = map.get(obj.getMyString());
if (other != null) {
other.setMyCount(other.getMyCount() + obj.getMyCount());
} else {
map.put(obj.getMyString(), obj);
}
}
List<MyClass> list = new ArrayList<>(map.values());

How do I sort an array of objects of different class types?

I am trying to develop a program that can sort an array of objects that are of different class types, but in the same hierarchy as one another. All of the objects are listed within the same array that I am trying to sort, and while I can alphabetically sort an array of objects that are of the same type easily enough, I cannot figure out how to sort everything all at once with the same Arrays.sort() method. Any help that anyone could provide would be greatly appreciated.
import java.util.Arrays;
public class Driver {
public static void main(String[] args) {
Vehicle[] machines = new Vehicle[3];//Example of an array that I can sort
machines[0] = new Vehicle("Giant Robot");
machines[1] = new Vehicle("Time Machine");
machines[2] = new Vehicle("Airplane");
Arrays.sort(machines);
for (int i = 0; i < machines.length; i++)
System.out.println(machines[i].getName());
Vehicle[] vehicles = new Vehicle[7];//example of an array that I cannot sort
vehicles[0] = new Car("Batmobile", 10);
vehicles[1] = new Helicopter("Batcopter", "x");
vehicles[2] = new Car("Jaguar", 6);
vehicles[3] = new Helicopter("RC Copter", "t");
vehicles[4] = new Car("Accelerator", 6);
vehicles[5] = new Helicopter("Stormshadow", "z");
vehicles[6] = new Car("Batmobile", 11);
}
}
**
public class Vehicle implements Comparable {
private String name;
public Vehicle(){
name = "no name";
}
public Vehicle(String newName){
name = newName;
}
public String getName(){
return name;
}
public int compareTo(Object o)
{
if ((o != null) &&
(o instanceof Vehicle))
{
Vehicle otherVehicle = (Vehicle) o;
return (name.compareTo(otherVehicle.name));
}
return -1;
}
}
**
public class Car extends Vehicle {
private int tireSize;
public Car(){
super();
tireSize = 0;
}
public Car(String newName, int newTireSize){
super(newName);
tireSize = newTireSize;
}
public int getSize(){
return tireSize;
}
}
**
public class Helicopter extends Vehicle {
private String bladeType;
public Helicopter(){
super();
bladeType = "none";
}
public Helicopter(String newName, String newBlade){
super(newName);
bladeType = newBlade;
}
public String getType(){
return bladeType;
}
}
Goal: You need to be able to compare a Vehicle to other of Vehicle.
To achieve that goal:
public class Vehicle implements Comparable<? extends Vehicle> {
....
public int compareTo(Object o) {
// Now, that the Comparable is for the type Vehicle
// you know that o is some kind of vehicle
// check vehicle related things
// number of seats, dogs, whatever
return -1;
}
}
You just need to adjust your code to:
class Vehicle implements Comparable<Vehicle> {
private String name;
/* ... */
#Override
public int compareTo(Vehicle vehicle) {
return name.compareTo(vehicle.getName());
}
}
In most cases, your classes should not implement Comparable, unless there is one and only one ordering that is always the correct one, like with numbers. Your vehicles can be sorted by name, by age, and probably by more criteria, so they should not implement Comparable.
Instead, you can pass the ordering function as a lambda function, at the time where you actually sort your vehicles:
Arrays.sort(machines, (left, right) -> left.getName().compareTo(right.getName()));
Or, equivalently:
Arrays.sort(machines, Comparator.comparing(Vehicle::getName));
This way you don’t need the implements Comparable anymore.
If you want to sort by vehicle type then you need to take class type into consideration, while sorting the element. Modify the compareTo() method as shown below:
public int compareTo(Object o){
if ((o != null) &&
(o instanceof Vehicle)){
Vehicle otherVehicle = (Vehicle) o;
return (otherVehicle.getClass().getSimpleName().equals(this.getClass().getSimpleName()) ?
name.compareTo(otherVehicle.name)
: otherVehicle.getClass().getSimpleName().compareTo(this.getClass().getSimpleName()));
}
return -1;
}

custom sorting order for a vector

I want to sort a vector based on user defined order.
here is my code snippet
class xxx {
private String xxName;
private String xxMapName
//getters and setter
}
// main
public class Test {
public static void main(String s) {
List<xxx> options = new Vector<xxx>();
scenarion1: (IF vector contains ISE_BASE,ISE_ADVANCED,ISE)
xxx x1 = new xxx();
x1.setXxName("s1");
x1.setXxMapName("ISE_BASE");
options.add(x1);
xxx x2 = new xxx();
x2.setXxName("s1");
x2.setXxMapName("ISE_ADVANCED");
options.add(x2);
xxx x2 = new xxx();
x2.setXxName("s1");
x2.setXxMapName("ISE");
options.add(x2);
scenarion2:(IF vector contains any two of ISE_BASE,ISE_ADVANCED,ISE)
xxx x1 = new xxx();
x1.setXxName("s1");
x1.setXxMapName("ISE_BASE");
options.add(x1);
xxx x2 = new xxx();
x2.setXxName("s1");
x2.setXxMapName("ISE_ADVANCED");
options.add(x2);
}
}
I want to sort vector based on xxMapName(property of xxx). Here the order should be always ISE_BASE,ISE,ISE_ADVANCED.
You can implement comparator interface and use
Collections.sort(List<T> list, Comparator<? super T> c)
Override compareTo()
class xxx implements Comparable<xxx> {
private String xxName;
private String xxMapName
//getters and setter
public int compareTo(xxx obj) {
if (this.xxMapName.equals("ISE_BASE")) {
return -1;
} else if (obj.xxMapName.equals("ISE_BASE")) {
return 1;
} else if (this.xxMapName.equals("ISE")) {
return -1;
} else if (obj.xxMapName.equals("ISE")) {
return 1;
} else if (this.xxMapName.equals("ISE_ADVANCED")) {
return -1;
} else if (obj.xxMapName.equals("ISE_ADVANCED")) {
return 1;
}
return 0;
}
}
after which you can use Collections.sort(options)

Categories

Resources