Remove duplicates (both values) - duplicate values from an ArrayList - java

I have an ArrayList with the following strings;
List<String> e = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
I want to check the list for duplicates and remove them from the list. In this case my list will only have two values, and in this example it would be the values 122 and 125, and the two 123s will go away.
What will be the best way to this? I was thinking of using a Set, but that will only remove one of the duplicates.

In Java 8 you can do:
e.removeIf(s -> Collections.frequency(e, s) > 1);
If !Java 8 you can create a HashMap<String, Integer>. If the String already appears in the map, increment its key by one, otherwise, add it to the map.
For example:
put("123", 1);
Now let's assume that you have "123" again, you should get the count of the key and add one to it:
put("123", get("aaa") + 1);
Now you can easily iterate on the map and create a new array list with keys that their values are < 2.
References:
ArrayList#removeIf
Collections#frequency
HashMap

You can also use filter in Java 8
e.stream().filter(s -> Collections.frequency(e, s) == 1).collect(Collectors.toList())

You could use a HashMap<String, Integer>.
You iterate over the list and if the Hash map does not contain the string, you add it together with a value of 1.
If, on the other hand you already have the string, you simply increment the counter. Thus, the map for your string would look like this:
{"123", 2}
{"122", 1}
{"125", 1}
You would then create a new list where the value for each key is 1.

Here is a non-Java 8 solution using a map to count occurrences:
Map <String,Integer> map = new HashMap<String, Integer>();
for (String s : list){
if (map.get(s) == null){
map.put(s, 1);
}
else {
map.put(s, map.get(s) + 1);
}
}
List<String> newList = new ArrayList<String>();
// Remove from list if there are multiples of them.
for (Map.Entry<String, String> entry : map.entrySet())
{
if(entry.getValue() > 1){
newList.add(entry.getKey());
}
}
list.removeAll(newList);

Solution in ArrayList
public static void main(String args[]) throws Exception {
List<String> e = new ArrayList<String>();
List<String> duplicate = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
for(String str : e){
if(e.indexOf(str) != e.lastIndexOf(str)){
duplicate.add(str);
}
}
for(String str : duplicate){
e.remove(str);
}
for(String str : e){
System.out.println(str);
}
}

The simplest solutions using streams have O(n^2) time complexity. If you try them on a List with millions of entries, you'll be waiting a very, very long time. An O(n) solution is:
list = list.stream()
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
.entrySet()
.stream()
.filter(e -> e.getValue() == 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
Here, I used a LinkedHashMap to maintain the order. Note that static imports can simplify the collect part.
This is so complicated that I think using for loops is the best option for this problem.
Map<String, Integer> map = new LinkedHashMap<>();
for (String s : list)
map.merge(s, 1, Integer::sum);
list = new ArrayList<>();
for (Map.Entry<String, Integer> e : map.entrySet())
if (e.getValue() == 1)
list.add(e.getKey());

List<String> e = new ArrayList<String>();
e.add("123");
e.add("122");
e.add("125");
e.add("123");
e.add("125");
e.add("124");
List<String> sortedList = new ArrayList<String>();
for (String current : e){
if(!sortedList.contains(current)){
sortedList.add(current);
}
else{
sortedList.remove(current);
}
}
e.clear();
e.addAll(sortedList);

I'm a fan of the Google Guava API. Using the Collections2 utility and a generic Predicate implementation it's possible to create a utility method to cover multiple data types.
This assumes that the Objects in question have a meaningful .equals
implementation
#Test
public void testTrimDupList() {
Collection<String> dups = Lists.newArrayList("123", "122", "125", "123");
dups = removeAll("123", dups);
Assert.assertFalse(dups.contains("123"));
Collection<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
dups2 = removeAll(123, dups2);
Assert.assertFalse(dups2.contains(123));
}
private <T> Collection<T> removeAll(final T element, Collection<T> collection) {
return Collections2.filter(collection, new Predicate<T>(){
#Override
public boolean apply(T arg0) {
return !element.equals(arg0);
}});
}
Thinking about this a bit more
Most of the other examples in this page are using the java.util.List API as the base Collection. I'm not sure if that is done with intent, but if the returned element has to be a List, another intermediary method can be used as specified below. Polymorphism ftw!
#Test
public void testTrimDupListAsCollection() {
Collection<String> dups = Lists.newArrayList("123", "122", "125", "123");
//List used here only to get access to the .contains method for validating behavior.
dups = Lists.newArrayList(removeAll("123", dups));
Assert.assertFalse(dups.contains("123"));
Collection<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
//List used here only to get access to the .contains method for validating behavior.
dups2 = Lists.newArrayList(removeAll(123, dups2));
Assert.assertFalse(dups2.contains(123));
}
#Test
public void testTrimDupListAsList() {
List<String> dups = Lists.newArrayList("123", "122", "125", "123");
dups = removeAll("123", dups);
Assert.assertFalse(dups.contains("123"));
List<Integer> dups2 = Lists.newArrayList(123, 122, 125,123);
dups2 = removeAll(123, dups2);
Assert.assertFalse(dups2.contains(123));
}
private <T> List<T> removeAll(final T element, List<T> collection) {
return Lists.newArrayList(removeAll(element, (Collection<T>) collection));
}
private <T> Collection<T> removeAll(final T element, Collection<T> collection) {
return Collections2.filter(collection, new Predicate<T>(){
#Override
public boolean apply(T arg0) {
return !element.equals(arg0);
}});
}

Something like this (using a Set):
Set<Object> blackList = new Set<>()
public void add(Object object) {
if (blackList.exists(object)) {
return;
}
boolean notExists = set.add(object);
if (!notExists) {
set.remove(object)
blackList.add(object);
}
}

If you are going for set then you can achieve it with two sets. Maintain duplicate values in the other set as follows:
List<String> duplicateList = new ArrayList<String>();
duplicateList.add("123");
duplicateList.add("122");
duplicateList.add("125");
duplicateList.add("123");
duplicateList.add("127");
duplicateList.add("127");
System.out.println(duplicateList);
Set<String> nonDuplicateList = new TreeSet<String>();
Set<String> duplicateValues = new TreeSet<String>();
if(nonDuplicateList.size()<duplicateList.size()){
for(String s: duplicateList){
if(!nonDuplicateList.add(s)){
duplicateValues.add(s);
}
}
duplicateList.removeAll(duplicateValues);
System.out.println(duplicateList);
System.out.println(duplicateValues);
}
Output: Original list: [123, 122, 125, 123, 127, 127]. After removing
duplicate: [122, 125] values which are duplicates: [123, 127]
Note: This solution might not be optimized. You might find a better
solution than this.

With the Guava library, using a multiset and streams:
e = HashMultiset.create(e).entrySet().stream()
.filter(me -> me.getCount() > 1)
.map(me -> me.getElement())
.collect(toList());
This is pretty, and reasonably fast for large lists (O(n) with a rather large constant factor). But it does not preserve order (LinkedHashMultiset can be used if that is desired) and it creates a new list instance.
It is also easy to generalise, to instead remove all triplicates for example.
In general the multiset data structure is really useful to keep in ones toolbox.

Related

Searching a Hashmap for values of type list, retrieving an element of list and adding it to a new Collection to return

i'm pretty new when it comes to Java but i'll hopefully clear this up.
I currently have one class and within that class i have a TreeMap called "departments" which takes an argument of >:
TreeMap <String, List<String>> department;
Within each department such as HR, Builders etc there are a list of names of people who work there. Such as:
HR: Janet, Jones, Bob
What i'd like to do is search through department to find all departments (keys) that contain someone who's called "bob" for instance and add them to a collection to make a return.
Can anyone help with this, i've been pulling my hair out for a few days! So far i'm this far with the method although clearly nowhere near complete!
public List<String> selectValues( String... aValue)
{
for(String eachDept : department.keySet()){
Collection<String> peopleInTheDept = department.get(eachDept);
for(String person : aValue){
if(peopleInTheDept.contains(person)){
result.add(person);
}
}
}
System.out.println(result);
}
Just like OH GOD SPIDERS predicted, there is a Java 8 stream solution:
TreeMap <String, List<String>> department = new TreeMap<>();
department.put("AB", Arrays.asList("Bob", "Truus", "Miep"));
department.put("CD", Arrays.asList("Jan", "Kees", "Huub"));
department.put("EF", Arrays.asList("Jan", "Piet", "Bert"));
String aValue = "Jan";
Map<String,List<String>> result = department.entrySet().stream()
// filter out those departments that don't contain aValue
.filter(entry -> entry.getValue().contains(aValue))
// collect the matching departments back into a map
.collect(Collectors.toMap(k -> k.getKey(), k -> k.getValue()));
// print the result
result.forEach((k,v)-> System.out.println(k + " " + v.toString()));
Which prints:
EF [Jan, Piet, Bert]
CD [Jan, Kees, Huub]
Pre Java 8 solution:
Map<String, List<String>> result2 = new TreeMap<>();
for(String eachDept : department.keySet()){
List<String> peopleInTheDept = department.get(eachDept);
if(peopleInTheDept.contains(aValue)){
result2.put(eachDept, department.get(eachDept));
}
}
for (String s : result2.keySet()){
System.out.println(s + " " + result2.get(s));
}
This prints exactly the same as my Java 8 code.
Here is some java 8 Streams fancy solution to get the information and fill your list.
public void selectValues(String... values)
{
for(String value : values) {
results.addAll(department.entrySet()
.stream()
.filter(entry -> entry.getValue().contains(value))
.map(entry -> entry.getKey())
.collect(Collectors.toList()));
}
}
What I understand that you need a list of department who's Value contain certain name. Here is the solution of Java 8 version.
public static void main(String[] args) {
// Initialization of map
Map<String, List<String>> department = new TreeMap<>();
department.put("HR", new ArrayList<>());
department.put("ACC", new ArrayList<>());
department.put("MK", new ArrayList<>());
department.get("HR").add("bob");
department.get("HR").add("John");
department.get("ACC").add("Kim");
department.get("ACC").add("bob");
department.get("MK").add("XXX");
// Here is the solution
// depts is a list of string which contains the name of
// department who's value contains 'bob'
List<String > depts = department.entrySet()
.stream()
.filter(i -> i.getValue().contains("bob"))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// Printing out the result
depts.stream().forEach(System.out::println);
}
In traditional way
List<String> depts = new ArrayList<>();
for (Map.Entry<String , List<String >> it :
department.entrySet()) {
if (it.getValue().contains("bob"))
depts.add(it.getKey());
}
Java8's streams is certainly an elegant solution...but if you are restricted with the use of java 8 then how about your departments be of type TreeMap<String, Set<String>>. If you insist in using a list its very similiar. Just change the Set to List. There is a contains method in List interface too.
TreeMap<String, List<String>> departments = new TreeMap<String, List<String>>();
ArrayList<String> myList = new ArrayList<String>();
myList.add("person1");
departments.put("dep1", myList);
String[] aValue = {"person1","person2"};
public void selectValues( String... aValue)
{
for(String eachDept : departments.keySet()){
List<String> peopleInTheDept = departments.get(eachDept);
for(String person : aValue){
if(peopleInTheDept.contains(person)){
result.add(person)
}
}
}
System.out.println(result);
}
Something similar to this maybe?

Split 1 ArrayList into multiple ones based on condition

I have a big ArrayList containing strings. I want to split it, based on a condition that an element meets. For example, it could be the string length if ArrayList contained String. What is the most efficient (not the easiest) way to do that ?
['a', 'bc', 'defe', 'dsa', 'bb']
after would result to :
['a'], ['bc', 'bb'], ['dsa'], ['defe']
It's easy and fairly efficient to do it using Java 8 streams:
Collection<List<String>> output = input.stream()
.collect(Collectors.groupingBy(String::length))
.values();
If you run it with this input:
List<String> input = Arrays.asList("a", "bc", "defe", "dsa", "bb");
You will get this output:
[[a], [bc, bb], [dsa], [defe]]
A non-stream version would do the same thing, i.e. build a Map<K, List<V>> where V is your value type (e.g. String in your case), and K is the type of the grouping value (e.g. Integer for the length).
Doing it yourself (like shown in answer by palako) might be slightly more efficient at runtime, but likely not in any way that matters.
Staying with Java 8, that would be this:
Map<Integer, List<String>> map = new HashMap<>();
for (String value : input)
map.computeIfAbsent(value.length(), ArrayList::new).add(value);
Collection<List<String>> output = map.values();
For earlier versions of Java, you can't use computeIfAbsent(), so:
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
for (String value : input) {
Integer length = Integer.valueOf(value.length()); // box only once
List<String> list = map.get(length);
if (list == null)
map.put(length, list = new ArrayList<String>());
list.add(value);
}
Collection<List<String>> output = map.values();
The most efficient way is to iterate the original list just once. What you do is you create buckets and add to those buckets.
public class Q1 {
public static void main(String[] args) {
String[] original = {"a","bc","defe","dsa","bb"};
List<String> originalValues = new ArrayList<String>(Arrays.asList(original));
Map<Integer, List<String>> orderedValues = new HashMap<Integer, List<String>>();
Iterator<String> it = originalValues.iterator();
while (it.hasNext()) {
String currentElement = it.next();
int length = currentElement.length();
if(!orderedValues.containsKey(length)) {
orderedValues.put(length, new ArrayList<String>());
}
orderedValues.get(length).add(currentElement);
}
System.out.println(orderedValues.values());
}
}
You might be tempted to use an array of arrays instead of a Map, and use the size of the string as the index to the array position, but then you need to watch out for a case where you don't have strings of a certain length. Imagine a case where you only have a string in the original list, but it has 100 characters. You would have 99 empty positions and one string in the array at position 100.

How to convert a Set<Set> to an ArrayList<ArrayList>

How would I add all the elements of a Set<<Set<String>> var to an ArrayList<<ArrayList<String>>? Of course I'm aware of the naive approach of just adding them.
private static ArrayList<ArrayList<String>> groupAnagrams(ArrayList<String> words){
ArrayList<ArrayList<String>> groupedAnagrams = new ArrayList<>();
AbstractMap<String, String> sortedWords = new HashMap<>();
Set<Set<String>> sameAnagramsSet = new HashSet<>();
for(String word : words){
char[] wordToSort = word.toCharArray();
Arrays.sort(wordToSort);
sortedWords.put(word, new String(wordToSort));
}
for(Map.Entry<String, String> entry: sortedWords.entrySet() ){
Set<String> sameAnagrams = new HashSet<>();
sameAnagrams.add(entry.getKey());
for(Map.Entry<String, String> toCompare : sortedWords.entrySet()){
if(entry.getValue().equals(toCompare.getValue())){
sameAnagrams.add(toCompare.getKey());
}
}
if(sameAnagrams.size()>0){
sameAnagramsSet.add(sameAnagrams);
}
}
//-->this line does not work! return new ArrayList<ArrayList<String>>(sameAnagramsSet);
}
With Java 8, you can do:
return sameAnagramsSet.stream()
.map(ArrayList::new)
.collect(toList());
although it returns a List<ArrayList<String>>.
What it does:
.stream() returns a Stream<Set<String>>
.map(ArrayList::new) is equivalent to .map(set -> new ArrayList(set)) and basically replaces each set by an array list
collect(toList()) places all the newly created lists in one list
Since you want to convert each element from a Set to an ArrayList, you'll have to do at least a little of this with an explicit loop, I think (unless you're using Java 8 or a third-party library):
Set<Set<String>> data = . . .
ArrayList<List<String>> transformed = new ArrayList<List<String>>();
for (Set<String> item : data) {
transformed.add(new ArrayList<String>(item));
}
Note that I changed the type of the transformed list from ArrayList<ArrayList<String>> to ArrayList<List<String>>. Generally it's preferable to program to an interface, but if you really need a list that must contain specifically instances of ArrayList, you can switch it back.

Want non duplicate elements from list

From following list I need only 'wow' and 'quit'.
List<String> list = new ArrayList();
list.add("test");
list.add("test");
list.add("wow");
list.add("quit");
list.add("tree");
list.add("tree");
you can check the frequency of an element in the Collection and rule out the elements which have frequency higher than 1.
List<String> list = new ArrayList<String>();
list.add("test");
list.add("test");
list.add("wow");
list.add("quit");
list.add("tree");
list.add("tree");
for(String s: list){
if(Collections.frequency(list, s) == 1){
System.out.println(s);
}
Output:
wow
quit
This snippet should leave you with a set (output) which contains only non-duplicated elements of your list.
HashSet<String> temp = new HashSet<String>();
HashSet<String> output = new HashSet<String>();
for (String element : list)
{
if (temp.contains(element)) output.remove(element);
else
{
temp.insert(element);
output.insert(element);
}
}
Operates in O(n*log(n)) time: one set of logarithmic operations (set lookups, inserts, etc) for each of the n elements in the list.
You can use HashMap impl to count occurences and select only onces that occur once.
e.g.
void check(List<String> list)
{
Map<String,Integer> checker = new HashMap<String,Integer>();
List<String> result = new ArrayList<String>();
for(String value: list)
{
Integer count = checker.get(value);
if (count==null)
{
count = 0;
}
checker.put(value, ++count);
}
// now select only values with count == 1
for(String value: checker.keySet())
{
if (checker.get(value) == 1)
{
result.add(value);
}
}
System.out.println(result);
}
And a Third way
List result = new ArrayList();
for(Object o : list){
if(list.indexOf(o) == list.lastIndexOf(o))
result.add(o);
}
Here is a Java 8 way without streams:
Map<String, Long> counts = new HashMap<>();
list.forEach(word -> counts.merge(word, 1L, Long::sum));
counts.values().removeIf(count -> count > 1);
This first iterates the list and stores the frequency of each word in the counts map. For this I'm using the Map.merge method, which either associates the provided value (1L in this case) with the given key (word here) or uses the provided merge function (Long::sum) to combine an existent value with the given one.
Then, words with a frequency greater than 1 are removed from the map via the Collection.removeIf method.
The whole process has O(n) time complexity.
Java 8+
list.stream() // Stream
.filter(i -> Collections.frequency(list, i) == 1) // Stream
.collect(Collectors.toList()) // List
.forEach(System.out::println); // void
It prints every element from that list that appears exactly once.
Details:
lambda expressions
Stream interface
Collections class
#ROMANIA_Engineer's solution should work just fine, but it does hide an O(n2) complexity in it, since Collections.frequency is an O(n) operation.
A more efficient solution that can still be squeezed in to a single statement could be to count how many times each item occurs and filter just items that appear once:
list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(e -> e.getValue() == 1L)
.map(Map.Entry::getKey)
.forEach(System.out::println);
List aList = Arrays.asList("test", "test",
"wow", "wow", "wow");
Set hashSet = new HashSet(aList);
hashSet.addAll(aList);
now you can print HashSet all the duplicates values removed
Easily clean a list using a lambda:
list.removeIf(element -> Collections.frequency(list, element) > 1);
If you're open to using a third-party library, the following can be used with Eclipse Collections:
List<String> list = Arrays.asList("test", "test", "wow", "quit", "tree", "tree");
Set<String> set = Bags.mutable.withAll(list).selectUnique();
System.out.println(set);
Outputs:
[wow, quit]
You can also construct a Bag directly instead of creating a List as follows:
MutableBag<String> bag =
Bags.mutable.with("test", "test", "wow", "quit", "tree", "tree");
MutableSet<String> set = bag.selectUnique();
Note: I am a committer for Eclipse Collections

Grouping elements of a list into sublists (maybe by using guava)

I want to group elements of a list. I'm currently doing it this way:
public static <E> List<List<E>> group(final List<E> list, final GroupFunction<E> groupFunction) {
List<List<E>> result = Lists.newArrayList();
for (final E element : list) {
boolean groupFound = false;
for (final List<E> group : result) {
if (groupFunction.sameGroup(element, group.get(0))) {
group.add(element);
groupFound = true;
break;
}
}
if (! groupFound) {
List<E> newGroup = Lists.newArrayList();
newGroup.add(element);
result.add(newGroup);
}
}
return result;
}
public interface GroupFunction<E> {
public boolean sameGroup(final E element1, final E element2);
}
Is there a better way to do this, preferably by using guava?
Sure it is possible, and even easier with Guava :) Use Multimaps.index(Iterable, Function):
ImmutableListMultimap<E, E> indexed = Multimaps.index(list, groupFunction);
If you give concrete use case it would be easier to show it in action.
Example from docs:
List<String> badGuys =
Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Function<String, Integer> stringLengthFunction = ...;
Multimap<Integer, String> index =
Multimaps.index(badGuys, stringLengthFunction);
System.out.println(index);
prints
{4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}
In your case if GroupFunction is defined as:
GroupFunction<String> groupFunction = new GroupFunction<String>() {
#Override public String sameGroup(final String s1, final String s2) {
return s1.length().equals(s2.length());
}
}
then it would translate to:
Function<String, Integer> stringLengthFunction = new Function<String, Integer>() {
#Override public Integer apply(final String s) {
return s.length();
}
}
which is possible stringLengthFunction implementation used in Guava's example.
Finally, in Java 8, whole snippet could be even simpler, as lambas and method references are concise enough to be inlined:
ImmutableListMultimap<E, E> indexed = Multimaps.index(list, String::length);
For pure Java 8 (no Guava) example using Collector.groupingBy see Jeffrey Bosboom's answer, although there are few differences in that approach:
it doesn't return ImmutableListMultimap but rather Map with Collection values,
There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned (source),
it's a bit more verbose than Guava + method reference.
EDIT: If you don't care about indexed keys you can fetch grouped values:
List<List<E>> grouped = Lists.transform(indexed.keySet().asList(), new Function<E, List<E>>() {
#Override public List<E> apply(E key) {
return indexed.get(key);
}
});
// or the same view, but with Java 8 lambdas:
List<List<E>> grouped = Lists.transform(indexed.keySet().asList(), indexed::get);
what gives you Lists<List<E>> view which contents can be easily copied to ArrayList or just used as is, as you wanted in first place. Also note that indexed.get(key) is ImmutableList.
// bonus: similar as above, but not a view, instead collecting to list using streams:
List<List<E>> grouped = indexed.keySet().stream()
.map(indexed::get)
.collect(Collectors.toList());
EDIT 2: As Petr Gladkikh mentions in comment below, if Collection<List<E>> is enough, above example could be simpler:
Collection<List<E>> grouped = indexed.asMap().values();
Collector.groupingBy from the Java 8 streams library provides the same functionality as Guava's Multimaps.index. Here's the example in Xaerxess's answer, rewritten to use Java 8 streams:
List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Map<Integer, List<String>> index = badGuys.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(index);
This will print
{4=[Inky], 5=[Pinky, Pinky, Clyde], 6=[Blinky]}
If you want to combine the values with the same key in some other way than creating a list, you can use the overload of groupingBy that takes another collector. This example concatenates the strings with a delimiter:
Map<Integer, String> index = badGuys.stream()
.collect(Collectors.groupingBy(String::length, Collectors.joining(" and ")));
This will print
{4=Inky, 5=Pinky and Pinky and Clyde, 6=Blinky}
If you have a large list or your grouping function is expensive, you can go parallel using parallelStream and a concurrent collector.
Map<Integer, List<String>> index = badGuys.parallelStream()
.collect(Collectors.groupingByConcurrent(String::length));
This may print (the order is no longer deterministic)
{4=[Inky], 5=[Pinky, Clyde, Pinky], 6=[Blinky]}
The easiest and simplest way would be using: Lamdaj grouping feature
The above example can be re-written:
List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Group group = group(badGuys, by(on(String.class).length)));
System.out.println(group.keySet());
With Java 8, Guava and few helper functions you can implement grouping with custom Comparator
public static <T> Map<T, List<T>> group(List<T> items, Comparator<T> comparator)
{
ListMultimap<T, T> blocks = LinkedListMultimap.create();
if (!ArrayUtils.isNullOrEmpty(items))
{
T currentItem = null;
for (T item : items)
{
if (currentItem == null || comparator.compare(currentItem, item) != 0)
{
currentItem = item;
}
blocks.put(currentItem, ObjectUtils.clone(item));
}
}
return Multimaps.asMap(blocks);
}
Example
Comparator<SportExercise> comparator = Comparator.comparingInt(SportExercise::getEstimatedTime)
.thenComparingInt(SportExercise::getActiveTime).thenComparingInt(SportExercise::getIntervalCount)
.thenComparingLong(SportExercise::getExerciseId);
Map<SportExercise, List<SportExercise>> blocks = group(sportWorkout.getTrainingExercises(), comparator);
blocks.forEach((key, values) -> {
System.out.println(key);
System.out.println(values);
});

Categories

Resources