How to create a summary of a list of objects? - java

I think it's a pretty basic question and there should be solutions out there, but I didn't manage to find any. I think I need more help in terminology, on what term I should look up to learn about my problem, but I really appreciate any help.
Anyway, I would like to implement the following:
I have a list of Objects. Each object is in the form of ExampleClass below:
public class ExampleClass {
private String name;
private Double firstDouble;
private Double secondDouble;
+ constructor and a bunch of methods
}
Basically I have a name variable and a bunch of numbers associated with each instance of ExampleClass. The name variable is not an id, so there may be several ExampleClasses in the list with the same name, all with different numbers associated with them. What I would like to do is to create a "summary" from this list:
Filtering out each instance of ExampleClass with the same name, so in my final list of objects, I do not have two objects with the same name variable.
I want to make operations with the Double variables of the objects with the same name.
So lets imagine I have the following ExampleClasses in my list:
ExampleClass first = new ExampleClass("apple",1,4);
ExampleClass second = new ExampleClass("pear",6,12);
ExampleClass third = new ExampleClass("apple",5,2);
ExampleClass fourth = new ExampleClass("peach",1,2);
ExampleClass fifth = new ExampleClass("plum",10,25);
In this case I want to remove from the list the first or third element, since they have the same name and I want to make an operation with the numbers, like adding up 1 and 5 and multiplying 4 and 2.
Thanks for any help in advance!
EDIT: I can solve it with a bunch of loops. However, I need my code to be readable and as efficient as it can get. I'm not looking for a brute force solution with nested loops, I'm interested if there is a nice, or nicer solution.

Finding the sum of all X values grouped by name is pretty easy in Java 8:
// Find the sum of X and group by name
Map<String, Integer> sumXByName = Stream.of(first, second, third, fourth, fifth)
.collect(groupingBy(ExampleClass::getName,
Collectors.<ExampleClass>summingInt(e -> e.getX())));
// Print the results
sumXByName.entrySet().stream()
.map(e -> e.getKey() + " -> " + e.getValue())
.forEach(System.out::println);
Prints:
plum -> 10
apple -> 6
pear -> 6
peach -> 1
However, finding the sum of X and product of Y requires a custom collector.
static class ExampleStatistics implements Consumer<ExampleClass> {
private Integer sum = 0;
private Integer product = null;
#Override
public void accept(ExampleClass value) {
sum += value.getX();
if (product == null) {
product = value.getY();
} else {
product *= value.getY();
}
}
public ExampleStatistics combine(ExampleStatistics other) {
sum += other.sum;
product *= other.product;
return this;
}
public Integer getSum() {
return sum;
}
public Integer getProduct() {
return product;
}
#Override
public String toString() {
return String.format("Sum X = %d, Product Y = %d", sum, product);
}
}
static class ExampleSummarizer
implements Collector<ExampleClass, ExampleStatistics, ExampleStatistics> {
#Override
public Supplier<ExampleStatistics> supplier() {
return ExampleStatistics::new;
}
#Override
public BiConsumer<ExampleStatistics, ExampleClass> accumulator() {
return (r, t) -> r.accept(t);
}
#Override
public BinaryOperator<ExampleStatistics> combiner() {
return (r, t) -> r.combine(t);
}
#Override
public Function<ExampleStatistics, ExampleStatistics> finisher() {
return i -> i; // identity finish
}
#Override
public Set<Collector.Characteristics> characteristics() {
return Stream.of(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED)
.collect(toSet());
}
};
Now you can easily summarize the objects:
// Summarize all examples and group by name
Map<String, ExampleStatistics> statsByName = Stream.of(first, second, third, fourth, fifth)
.collect(groupingBy(ExampleClass::getName, new ExampleSummarizer()));
Printing this map will yield the following:
plum -> Sum X = 10, Product Y = 25
apple -> Sum X = 6, Product Y = 8
pear -> Sum X = 6, Product Y = 12
peach -> Sum X = 1, Product Y = 2
EDIT: I used integers for convenience. However, there are summarizing equivalents available for doubles e.g. summingDouble.
class ExampleClass {
private final String name;
private final Integer x;
private final Integer y;
public ExampleClass(String name, Integer x, Integer y) {
super();
this.name = name;
this.x = x;
this.y = y;
}
public String getName() {
return name;
}
public Integer getX() {
return x;
}
public Integer getY() {
return y;
}
}

Filtering out each instance of ExampleClass with the same name, so in my final list of objects, I do not have two objects with the same name variable.
Consider making your class implement equals(Object obj) and Comparable interface or provides some means of creating a Comparator object.
Implement a SortedSet collection for your list such as TreeSet
I want to make operations with the Double variables of the objects
with the same name.
You could use the contains(Object obj) method provided by any Set inherited collection before adding an item to your list so that if the method returns true, you could do something with the duplicate. It is recommended that you keep your equals implementation consistent with your Comparable implementation.

Instead of
ExampleClass first = new ExampleClass("apple",1,4);
ExampleClass second = new ExampleClass("pear",6,12);
ExampleClass third = new ExampleClass("apple",5,2);
ExampleClass fourth = new ExampleClass("peach",1,2);
ExampleClass fifth = new ExampleClass("plum",10,25);
use List
List<ExampleClass> list = new ArrayList<>(5);
list.add(new ExampleClass("apple",1,4));
...
delete the first or third element
list.remove(1);
list.remove(3);
Other you can do by yourself, I think. You should just read about List, Map, Set and so on.

Related

Priority Queue of user defined objects

I wanna create priority queue of objects according to their attributes. how can I compare the queue according to spesific attributes. for example if i type somewhere id, queue is designed for id. i have two different java file below. I wanna get all possible queues by comparing attributes of objects.
first
public class customers {
int id;
String name;
int age;
double money;
public customers(int id, String name, int age, double money) {
this.id = id;
this.name = name;
this.age = age;
this.money = money;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
main file starts now
import java.util.ArrayList;
import java.util.PriorityQueue;
public class draft {
public static void main(String[] args) {
PriorityQueue<customers> customerList= new PriorityQueue<>();
customers customer1= new customers(0,"jack",30,180.5);
customers customer2= new customers(1,"john",52,800.3);
customers customer3= new customers(2,"alice", 41, 400.5);
customerList.add(customer1);
customerList.add(customer2);
customerList.add(customer3);
for (customers c:customerList
) {
System.out.println(c.getId());
}
}
}
I want a simple solution like this. the code below is not valid but i can not understand complex codes. and i think there has to be a simple solution as this.
PriorityQueue<customers> customerList= new PriorityQueue<>(customers.age);
i do not know if i explained the question. for example if i compare objects id, the queue should be object#0,object#1,object#2 in this order. if i compare objects's age the queue will be object#0, object#2,object#1
Here are few ways to maintain a PriorityQueue based on any field of a particular class.
Below is an illustration to define a PriorityQueue sorted according to the field id (sorted in ascending order):
public static void main(String[] args)
{
// Method 1] Using Custom Comparator
PriorityQueue<Customers> pq1 = new PriorityQueue<Customers>(Comparator.comparing(Customers::getId));
Customers customer1 = new Customers(0,"jack",30,180.5);
Customers customer2 = new Customers(1,"john",52,800.3);
Customers customer3 = new Customers(2,"alice", 41, 400.5);
pq1.add(customer1);
pq1.add(customer2);
pq1.add(customer3);
// Method 2] Using Lambda Operator
PriorityQueue<Customers> pq2 = new PriorityQueue<>((x, y) -> x.id-y.id);
//Method 3] Custom Comparator again
PriorityQueue<Customers> pq3 = new PriorityQueue<>(new Comparator<Customers>()
{
#Override
public int compare(Customers a, Customers b)
{
return a.id-b.id;
}
});
pq2.addAll(pq1);
pq3.addAll(pq1);
System.out.println(pq1);
System.out.println(pq2);
System.out.println(pq3);
}
Output:
[(0 , jack , 30 , 180.5), (1 , john , 52 , 800.3), (2 , alice , 41 , 400.5)]
[(0 , jack , 30 , 180.5), (1 , john , 52 , 800.3), (2 , alice , 41 , 400.5)]
[(0 , jack , 30 , 180.5), (1 , john , 52 , 800.3), (2 , alice , 41 , 400.5)]
Similarly you can design other queues based on any field of your choice.
To maintain the priority queue in reverse order (Decreasing/Descending order), we need to reverse the orders in the comprators like:
PriorityQueue<Customers> pq2 = new PriorityQueue<>((x, y) -> y.id-x.id);
Please note, for ascending it was: (x, y) -> x.id-y.id
for descending it will be: (x, y) -> y.id-x.id
Using custom Comparator:
PriorityQueue<Customers> pq3 = new PriorityQueue<>(new Comparator<Customers>()
{
#Override
public int compare(Customers a, Customers b)
{
return b.id-a.id; // reversed
}
});
And if you want to sort the priority queue based on two fields, let say age & id in such a way that if multiple age's are equal, then priority is given to id.
You can achieve the above in the following ways:
public static void main(String[] args)
{
// Method 1] Using Custom Comparator (Increasing order)
PriorityQueue<Customers> pq1 = new PriorityQueue<Customers>(Comparator.comparing(Customers::getAge).thenComparing(Customers::getId));
Customers customer1 = new Customers(0,"jack",30,180.5);
Customers customer2 = new Customers(1,"john",52,800.3);
Customers customer3 = new Customers(2,"alice", 41, 400.5);
pq1.add(customer1);
pq1.add(customer2);
pq1.add(customer3);
// Method 2] Using Lambda Operator (Increasing order)
PriorityQueue<Customers> pq2 = new PriorityQueue<>((x, y) -> (x.age == y.age) ? x.id-y.id : x.age-y.age);
//Method 3] Custom Comparator again (Reverse order)
PriorityQueue<Customers> pq3 = new PriorityQueue<>(new Comparator<Customers>()
{
#Override
public int compare(Customers a, Customers b)
{
return (a.age == b.age) ? b.id-a.id : b.age-a.age;
}
});
pq2.addAll(pq1);
pq3.addAll(pq1);
System.out.println(pq1);
System.out.println(pq2);
System.out.println(pq3);
}
For sorting based on age & money, few modifications are required as money is of double dataType. Below is how you can achieve the desired:
PriorityQueue<Customers> pq1 = new PriorityQueue<Customers>(Comparator.comparing(Customers::getAge).thenComparing(Customers::getMoney));
PriorityQueue<Customers> pq2 = new PriorityQueue<>((x, y) -> (x.age == y.age) ? Double.compare(x.money,y.money) : x.age-y.age);
PriorityQueue<Customers> pq3 = new PriorityQueue<>(new Comparator<Customers>()
{ #Override
public int compare(Customers a, Customers b)
{
return (a.age == b.age) ? Double.compare(a.money,b.money) : a.age-b.age;
}
});
Use the poll method to verify the order of elements in the priorityQueue.
All the implementations are easy to understand. But if you are having a tough time understanding it, please reach out.
The way to do this would be to use multiple Comparator classes. Comparator gives us a way to define HOW we want our objects to be compared to each other - in your case, it could be id,age etc.
public class Comparator<Customer> CustomerAgeComparator implements Comparator<Customer>() {
public int compare(Customer user1, Customer user2) {
int userPoints1 = user1.getAge();
int userPoints2 = user2.getAge();
if (userPoints1 == userPoints2)
return 0;
else if (userPoints1 > userPoints2)
return 1;
else
return -1;
}
};
The above comparator will sort customers in descending order of age.
Then you need to pass this information to your Priority Queue somehow. Luckily PriorityQueue has a constructor that allows one to do just that. Call it in the following manner :
PriorityQueue oldestCustomerFirst = PriorityQueue<String>(new CustomerAgeComparator);

Sort List of Objects by values from array;

I have a List<Brand> categories; with 1000+ items.
For each item from the list I have id, to get that I use categories.getId();
And I have an array int[] sortedIdArr = {4,53,102,403,110,5,6,8,12};
I would like to sort my categories list and make order by id how it is in sortedIdArr.
How can I implement that ?
private void sortBrandsById(List<Brand> categories) {
Collections.sort(categories, new Comparator<Brand>() {
public int compare(Brand o1, Brand o2) {
}
});
}
Can I use Collections.sort ?
Typically you would use Collections.sort, or the equivalent idioms in Java 8 if applicable, or a sorted Collection such as TreeSet.
However in this case you want to follow a pre-defined order, dictated by your sortedIdArr array.
One way to achieve that is to use a linked collection (e.g. a LinkedHashSet).
Then you iterate your sortedIdArr array, and search your List<Brand> for an object with the given ID.
If found, you add the Brand object with the given ID to your LinkedHashSet, which will retain the insertion order.
Note that if an ID is not found, your Set will not exactly "match" the array.
Self-enclosed example, using Java 8
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
public class Main {
// simplified Brand pojo
static class Brand {
int id;
public Brand(int id) {
this.id = id;
}
public int getId() {
return id;
}
// for output clarity
#Override
public String toString() {
return String.format("Brand: %d", id);
}
}
public static void main(String[] args) throws Exception {
// simplified ID list
int[] sortedIdArr = {4,53,102};
// "randomly" ordered Brand list
final List<Brand> categories = new ArrayList<Brand>() {
{
add(new Brand(1));
add(new Brand(102));
add(new Brand(53));
add(new Brand(4));
add(new Brand(0));
}
};
// destination: linked set
Set<Brand> linked = new LinkedHashSet<Brand>();
// streaming the ID array in order
Arrays.stream(sortedIdArr)
.forEach((i) -> {
// retrieving a Brand with same ID as the current
// from the "randomly" ordered list
Optional<Brand> toAdd = categories.stream()
.filter((b) -> b.getId() == i)
.findFirst();
// making sure there's one
if (toAdd.isPresent()) {
// adding to linked set
linked.add(toAdd.get());
}
}
);
System.out.println(linked);
}
}
Output
[Brand: 4, Brand: 53, Brand: 102]
Imperative idiom for older Java versions
for (int i: sortedIdArr) {
for (Brand b: categories) {
// assuming no nulls
if (b.getId() == i) {
linked.add(b);
break;
}
}
}
Yes you can use the Collections.sort()
To sort your Brand using id :
public int compare(Brand o1, Brand o2) {
return o1.getId().compareTo(o2.getId());
}
To sort your Brand using the array of id sortedIdArr :
Implement the Comparator Class :
class C implements Comparator<A> {
int[] idOrder;
public C(int[] idOrder) {
super();
this.idOrder = idOrder;
}
#Override
public int compare(A o1, A o2) {
Integer indexofO1 = Arrays.binarySearch(idOrder, o1.getId());
Integer indexofO2 = Arrays.binarySearch(idOrder, o2.getId());
return indexofO1.compareTo(indexofO2);
}
}
The key idea here is to inverse the process and compare using the index of the id instead of the id itself !
To use it :
Collections.sort(list, new C (idOrder));
Test Example :
int[] idOrder = new int [] {3,1,2};
List<A> list = new ArrayList<>();
list.add(new A(1));
list.add(new A(2));
list.add(new A(3));
System.out.println(list);
//Output : [A [id=1], A [id=2], A [id=3]]
Collections.sort(list, new C(idOrder));
System.out.println(list);
//Output : [A [id=3], A [id=1], A [id=2]]
You can do it with Collections.sort(...) but I strongly recommend not to go for Comparator method in this situation with this number of items in your list.
You can have a loop on your List<Brand> categories and add them in a HashMap<Integer,Brand> named tempMap. Then use it for lookup them in the order of your sortedIdArr array. Change your sort method like this:
private void sortBrandsById(List<Brand> categories, int [] sortedIdArr) {
HashMap<Integer,Brand> tempMap = new HashMap<Integer, Brand>(categories.size());
for (int i = 0; i < categories.size(); i++) {
tempMap.put(categories.get(i).getId(), categories.get(i));
}
categories = new ArrayList<Brand>(sortedIdArr.length);
for (int i = 0; i < sortedIdArr.length; i++) {
categories.add(tempMap.get(sortedIdArr[i]));
}
}
This way of sorting is from order O(n) for creating the tempMap + O(n) for recreating the category list. Although, the O(1) is not guaranteed for HashMap's get/put operations, java's decent hashing implementation very good and reliable. So the total complexity can not be very greater than O(n). At least it is very better than O(n^2). Time complexity is very important and I don't think you can find a way better than something very near O(n) complexity.
Hope this would be helpful.
You can use the following code(You need the Apache commons lang jar-otherwise you have to iterate through your array to find the index).
private static void sortBrandsById(List<Brand> categories,int[] array) {
Collections.sort(categories, new Comparator<Brand>() {
public int compare(Brand o1, Brand o2) {
return ArrayUtils.indexOf(array,o1.getId())-ArrayUtils.indexOf(array,o2.getId());
}
});
}
If you are able to put your predefined sorting order in a list not in an array , it will be much easier.

Java order by priority list

Given a list of objects (List<MyClass> objects).
class MyClass {
int id;
String name;
}
And a list with names:
name1
name2
name3
Whats a nice way to write a comparator to use the list of names as a priority list and if a priority doesnt exist for a name use alphabetic ordering?
I would suggest, that you use the java.util.Collections.sort method, and provide a custom comparator.
// Define a new static comparator attribute for your class
public static Comparator<MyClass> MY_COMPARATOR = new Comparator<>() {
#Override
public int compare(MyClass o1, MyClass o2) {
return o1.name.compareTo(o2.name); // or whatever logic
}
};
//Then just call this to sort when you need it
List<MyClass> myList; // initialised somewhere
Collections.sort(myList, MY_COMPARATOR);
If you're using java 8+, then the code to create the comparator is even shorter:
public static Comparator<MyClass> MY_COMPARATOR = (o1, o2) -> o1.name.compareTo(o2.name);
Put the strings into an array and loop through it to see which one you encounter first.
public class NameComparator implements Comparator {
static private [] String strNames = {"Ken", "Alisia", "Ben"};
public int compare(MyClass objX, MyClass objY) {
String x = objX.Name;
String y = objY.Name;
String strCurrentName;
if(x.equals(y)) {
return 0;
}
for(strCurrentName: strNames) {
if(strCurrentName.equals(x)) {
return 1;
}
if(strCurrentName.equals(y)) {
return -1;
}
}
return x.compareTo(y);
}
}
Sorting with this comparator would give you, for instance, "Ken", "Alicia", "Michelle" and "Nancy".
If speed is an issue you could put the names in a HashMap instead of an array. The code would then be quite different, I can give you an example if you are interested.

Add Key and Value into an Priority Queue and Sort by Key in Java

I am trying to take in a List of strings and add them into a Priority Queue with Key and Value. The Key being the word and the value being the string value of the word. Then I need to sort the queue with the highest string value first. The priority queue is not letting me add 2 values.
public static List<String> pQSortStrings(List<String> strings) {
PriorityQueue<String, Integer> q = new PriorityQueue<>();
for (int x = 0; x < strings.size(); x++) {
q.add(strings.get(x),calculateStringValue(strings.get(x)));
}
return strings;
}
Problem
PriorityQueue can store a single object in it's each node. So what you are trying to do can not be done as it is.
But you can compose both objects in a single class and then use the PriorityQueue.
You would either need to supply a Comparator or rely on natural ordering by implementing Comparable interface.
Solution
Create a class which has String and int as it's members.
public class Entry {
private String key;
private int value;
// Constructors, getters etc.
}
Implement Comparable interface and delegate comparison to String.
public class Entry implements Comparable<Entry> {
private String key;
private int value;
public Entry(String key, int value) {
this.key = key;
this.value = value;
}
// getters
#Override
public int compareTo(Entry other) {
return this.getKey().compareTo(other.getKey());
}
}
Build the PriorityQueue using this class.
PriorityQueue<Entry> q = new PriorityQueue<>();
Add elements as following.
q.add(new Entry(strings.get(x), calculateStringValue(strings.get(x))));
Hope this helps.
Using Java-8
PriorityQueue<Map.Entry<String, Integer>> queue = new PriorityQueue<>(Map.Entry.comparingByValue(Comparator.reverseOrder()));
to add a new Entry
queue.offer(new AbstractMap.SimpleEntry<>("A", 10));
Solution
public static List<String> pQSortStrings(List<String> strings) {
Queue<String> pq = new PriorityQueue<>((a, b) ->
calculateStringValue(b) - calculateStringValue(a));
for (String str : strings) {
pq.add(str);
}
return strings;
}
Explanation
I believe that the cleanest way to do this is to store Strings in your pq and use a small custom Comparator.
In this case, we want to use calculateStringValue and the pq should return highest String values first. Therefore, make a pq of entries and use the following Comparator:
1 Queue<String> pq = new PriorityQueue<>(new Comparator<String>() {
2 #Override
3 public int compare(String a, String b) {
4 return calculateStringValue(b) - calculateStringValue(a);
5 }
6 });
7 for (String str : strings) {
8 pq.add(str);
9 }
10 return strings;
Simpler syntax for the Comparator, replacing lines 1 - 6, is:
Queue<String> pq = new PriorityQueue<>((a, b) ->
calculateStringValue(b) - calculateStringValue(a));
If you wanted to return smallest String values first, you could just switch the order around for a and b in the Comparator:
...new PriorityQueue<>((a, b) -> calculateStringValue(a) - calculateStringValue(b));
In general, the pattern a - b sorts by smallest first, and b - a sorts by largest values first.
Many good answers are already present but I am posting this answer because no one has used hashmap in their answers.
You can also make the priority Queue from HashMaps bellow is the example for the same. I am creating a max priority queue.
Mind well here I am considering that your hashmap contains only one Entry
PriorityQueue<HashMap<Character, Integer>> pq = new PriorityQueue<>((a, b) -> {
char keyInA = a.keySet().iterator().next(); // key of a
char keyInB = b.keySet().iterator().next(); // key of b
return b.get(keyInB) - a.get(keyInA);
});
For Insertion of the value in the priority queue.
pq.add(new HashMap<>() {
{
put('a', 0);
}
});
Define a class with a key field and a value field
Class MyClass{
int key;
String value
}
Queue<MyClass> queue = new PriorityQueue<>(Comparotor.comparingInt(a -> a.key));
Adding to #Tanmay Patil Answer, If you are using Java 8, You can use lambda for more concise code as comparator interface is a functional interface.
public class CustomEntry {
private String key;
private int value;
public CustomEntry(String key, int value) {
this.key = key;
this.value = value;
}
// getters etc.
}
Now below is the updated code
public static List<String> pQSortStrings(List<String> strings) {
PriorityQueue<CustomEntry> q = new PriorityQueue<>((x, y) -> {
// since you want to sort by highest value first
return Integer.compare(y.getValue(), x.getValue());
});
for (int x = 0; x < strings.size(); x++) {
q.add(new CustomEntry(strings.get(x),calculateStringValue(strings.get(x))));
}
return strings;
}
To use this priority queue
CustomEntry topEntry = q.peek();
System.out.println("key : " + topEntry.getKey());
System.out.println("value : " + topEntry.getValue());
Same logic can be also be applied by using Map.Entry<String, Integer> provided by java for storing key, pair value

Sort List based on index value

This is what i have so far, i'm trying to sort a bunch of List<String>'s based on the value of an index.
LinkedHashSet<List<String>> sorted = new LinkedHashSet<List<String>>();
How do i sort the LinkedHashSet in order from Highest to Lowest index 2 value of the List's?
Example input:
List<String> data1 = Database.getData(uuid);
double price = Double.valueOf(data1.get(2))
data1.add("testval");
data1.add("testval");
data1.add("100.00");
sorted.add(data1);
and on another seperate List:
List<String> data2 = Database.getData(uuid);
double price = Double.valueOf(data2.get(2))
data2.add("anotherval");
data2.add("anotherval");
data2.add("50.00");
sorted.add(data2);
Output of the sorted LinkedHashSet in descending order.
testval testval 100.00
anotherval anotherval 50.00
Sorry if this is confusing, im not sure where to go about sorting like this.
Create a new class to represent you complex objects. There is no need to store multiple values in a list when you can do it in objects.
public class ComplexObject {
private String description1;
private String description2;
private Double value;
public ComplexObject(String description1, String description2, Double value) {
this.description1 = description1;
this.description2 = description2;
this.value = value;
}
public void setDescription1(String description1) {
this.description1 = description1;
}
public String getDescription1() {
return description1;
}
public void setDescription2(String description2) {
this.description2 = description2;
}
public String getDescription2() {
return description2;
}
public void setValue(Double value) {
this.value = value;
}
public Double getValue() {
return value;
}
}
Then add elements to the list and sort it using a new, custom, comparator:
public static void main(String[] args) {
List<ComplexObject> complexObjectList = new ArrayList<ComplexObject>();
//add elements to the list
complexObjectList.add(new ComplexObject("testval","testval",100.00d));
complexObjectList.add(new ComplexObject("anotherval","anotherval",50.00d));
//sort the list in descending order based on the value attribute of complexObject
Collections.sort(complexObjectList, new Comparator<ComplexObject>() {
public int compare(ComplexObject obj1, ComplexObject obj2) {
return obj2.getValue().compareTo(obj1.getValue()); //compares 2 Double values, -1 if less , 0 if equal, 1 if greater
}
});
//print objects from sorted list
for(ComplexObject co : complexObjectList){
System.out.println(co.getDescription1()+" "+co.getDescription2()+" "+co.getValue());
}
}
Output:
testval testval 100.0
anotherval anotherval 50.0
Firstly, you shouldn't use a LinkedHashSet but a TreeSet. LinkedHashSet will retain the insertion order without sorting.
Secondly, you need to initialize your TreeSet with a Comparator that compares based on whichever value of your List is required, that is, if you know the index of the String that will represent a double value in advance. Otherwise I would recommend using custom objects instead of List.
If you decide to use custom objects, you don't necessarily need to initialize your TreeSet with a Comparator as second argument.
Instead, you could have your custom objects implement Comparable, and implement a one-time comparation logic there.
It all depends on whether you only need to sort in a particular order.
Finally, custom objects will require you to override equals and hashCode.
First, and extracted from Oracle's Java reference:
This linked list defines the iteration ordering, which is the order in which elements were inserted into the set
So you can't sort your data just inserting it into the LinkedHashSet.
You may be confusing that set implementation with SortedSet. SortedSet allows you to pass a comparator which will determine the elements order in the data structure.
On the other hand, I don't know whether you chose you List<String> arbitrarily but it seems to me a wiser option to aggregate your the 3 strings as a class attributes. The point is that, if your elements are always going to be 3 elements, being the last one a double value: Why do you need a dynamic structure as a List?
EDIT
Here you have a possible better implementation of what you want:
public class Element
{
public Element(String a, String b, double val) {
this.a = a;
this.b = b;
this.val = val;
}
#Override
public String toString() {
return a + "\t" + b + "\t" + val;
}
public String a;
public String b;
public double val;
}
And you can use this class to store your elements. An example of use:
SortedSet<Element> sorted = new TreeSet<>(new Comparator<Element>() {
#Override
public int compare(Element o1, Element o2) {
return (new Double(o1.val)).compareTo(o2.val);
}
});
sorted.add(new Element("testval", "testval", 100.0));
sorted.add(new Element("anotherval", "anotherval", 50.0));
for(Element el: sorted)
{
System.out.println(el);
}
Note that the comparator is given as an instance of an anonympous inner class implementing Java's Comparator interface.

Categories