Reputation: 103
I created a class name objectA that has lets say 4 variable: Date time; String text; int var1, int var2
I need to create a list of ObjectA(). And then group them first by Time, second by var1, and then by var2. This is because i want to be able to compare lists that has different var2 but the same var1; or lists that has the same var2 but different var1.
I end up using "List< List< List< objectA>>>" which works fine i guess, but it doesnt looks great. And i dont think this is a good practice. Does anyone know any Datastructure or Tree or other ideas with which i could implement instead of List within List within List.
Almost similar question has actually been ask here: List of Lists of Lists .But the answer are just not what i was looking for. Please pardon me if this is still consider against the rule.
Upvotes: 1
Views: 526
Reputation: 925
If that's always the way you want to sort; by time, then val1, then val2, implement Comparable in your ObjectA class. Something like
public int compareTo(Object that) {
//check for null
// check for instanceOf ObjectA
// cast from Object to ObjectA
int result = this.time.compareTo(that.time);
if (result == 0) {
// time comparison was the same
result = this.var1.compareTo(that.var1);
if (result == 0) {
// time and var1 comparisons were the same
result = this.var2.compareTo(that.var2)
}
}
return result;
}
and then just sort() one list.
Upvotes: 0
Reputation: 34460
The ideal structure to group objects by some attribute is a Map
of List
s, where each key of the map corresponds to each different value of the attribute along the list of objects, and each value of the map is a sublist of all the objects whose attribute matches the key.
Let's start grouping by a single attribute. Using streams is quite easy to accomplish what you want:
Map<Date, List<ObjectA>> groupsByDate =
yourList.stream()
.collect(Collectors.groupingBy(ObjectA::getTime));
This assumes ObjectA
has a getTime
method.
Now, Collectors.groupingBy
has an overloaded version that accepts what is called a downstream collector, meaning that you can collect the objects that match a value into another structure different than a List
.
For example, you can collect to a second Map
that groups objects by a second criteria, in your case this would be by var1
:
Map<Date, Map<String, List<ObjectA>>> groupsByDateAndVar1 =
yourList.stream()
.collect(Collectors.groupingBy(
ObjectA::getTime,
Collectors.groupingBy(ObjectA::getVar1)));
This assumes ObjectA
has also a getVar1
method.
Finally, if you need to group by a third nested criteria, you could do it in a similar way:
Map<Date, Map<String, Map<String, List<ObjectA>>>> groupsByDateAndVar1AndVar2 =
yourList.stream()
.collect(Collectors.groupingBy(
ObjectA::getTime,
Collectors.groupingBy(
ObjectA::getVar1,
Collectors.groupingBy(ObjectA::getVar2))));
This assumes ObjectA
has also a getVar2
method.
Upvotes: 1
Reputation: 543
a List<List<Object>>
is probably what you want if you want to group by the first variable and then subgroup by the second
You could also do a Tree, up to you
Upvotes: 0
Reputation: 2352
This is an example of a simple tree structure for your problem.
public class Tree {
private Node root;
public Tree(List<YourObject> rootData) {
root = new Node();
root.data = rootData;
root.children = new ArrayList<Node>();
}
public static class Node {
private List<YourObject> data;
private Node parent;
private List<Node> children;
}
}
Your can build a simple tree and run all tree and graph-algorithms on this simple structure.
Upvotes: 2