Java group by arraylist

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

Sure it is possible, and even easier with Guava 🙂 Use Multimaps.index(Iterable, Function) :

ImmutableListMultimap indexed = Multimaps.index(list, groupFunction); 

If you give concrete use case it would be easier to show it in action.

List badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde"); Function stringLengthFunction = . ; Multimap index = Multimaps.index(badGuys, stringLengthFunction); System.out.println(index); 

In your case if GroupFunction is defined as:

GroupFunction groupFunction = new GroupFunction() < @Override public String sameGroup(final String s1, final String s2) < return s1.length().equals(s2.length()); >> 

then it would translate to:

Function stringLengthFunction = new Function() < @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 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:

There are no guarantees on the type, mutability, serializability, or thread-safety of the Map returned (source),

EDIT: If you don’t care about indexed keys you can fetch grouped values:

List> grouped = Lists.transform(indexed.keySet().asList(), new Function>() < @Override public Listapply(E key) < return indexed.get(key); >>); // or the same view, but with Java 8 lambdas: List> grouped = Lists.transform(indexed.keySet().asList(), indexed::get); 

what gives you Lists> 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> grouped = indexed.keySet().stream() .map(indexed::get) .collect(Collectors.toList()); 

EDIT 2: As Petr Gladkikh mentions in comment below, if Collection> is enough, above example could be simpler:

Collection> grouped = indexed.asMap().values(); 

Источник

Java (ArrayList) : Grouping a list of persons by name [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.

Foo, scientist Foo, teacher Bar, student 
Foo, scientist, teacher Bar, student 

Thanks for your comment : Well, I’m looking for a clean method/library that can do the job (grouping data by name and then putting its related values side by side) instead of doing loops.

6 Answers 6

If you are looking for a clean library, with emaze-dysfunctional you can write

Groups.groupBy(persons, new Pluck(Person.class, "occupation")) 

In my case, I followed this answer and able to get the groups in console. How to save the arraylists in separate variable. I have 3 groups.

That can be solved in a number of ways. I would probably use Map object, say

Map> occupationsByName = new LinkedHashMap>(0); 

I would then loop through the list of persons, using the names as keys to the Map object and initialising the List object whenever I find the key does not previously exist in the Map say,

for ( Iterator persons = personsList.iterator(); persons.hasNext() ) < String person = persons.next().getName(); if ( occupationsByName.containsKey( person ) ) < occupationsByName.get( person ).add( person.getOccupation() ); >else < occupationsByName.put(person, new ArrayList(0) ); occupationsByName.get( person ).add( person.getOccupation() ); > > 

I would then add the occupations to the List under the each key, then end by finally printing out the Map.

I have to state that I am making an assumption you know how to use the collection classes, and even if you do not, you can make use of the Java API

This test case passes for me:

package com.sandbox; import com.google.common.base.Joiner; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Multimap; import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; public class SandboxTest < @Test public void testQuestionInput() < Listpersons = new ArrayList(); persons.add(new Person("Foo", "scientist")); persons.add(new Person("Foo", "teacher")); persons.add(new Person("Bar", "student")); String outputString = getOutputString(persons); assertEquals("Foo, scientist, teacher\n" + "Bar, student\n", outputString); > private String getOutputString(List in) < Multimapmap = LinkedListMultimap.create(); for (Person person : in) < map.put(person.name, person.occupation); >StringBuilder buf = new StringBuilder(); Joiner joiner = Joiner.on(", "); for (String key : map.keySet()) < buf.append(key).append(", ").append(joiner.join(map.get(key))).append("\n"); >return buf.toString(); > class Person < Person(String name, String occupation) < this.name = name; this.occupation = occupation; >private String name; private String occupation; /* Getters and setters*/ /* toString method */ > > 

It takes the list of Persons and passes them into a Multimap. The Multimap comes from the Google guava library.

But, you might want to use maurocchi’s answer. it’s much cleaner than this.

If you have two Person instances that have the same name but different occupation and you consider them to be the same person then you’ll need to tell JVM that if two names are equal then those to people are also equal. THat you do by overriding equals()

Now the second step is to update the list so that once you try to add a Person which already exist in the list (i.e. there is a person that has the same name) then you add the new occupation onto the old one (e.g. by string concatenation).

You don’t need any libraries for what you want to do, just need to write complete classes. 🙂

Источник

Group list elements in list of list in java

I have a list of elements. I want to group the elements of this list into a list of list based on some condition. Is it possible to do it easily in java ?

public class CollectionTest < public static void main(String[] arg) < Target target0 = new Target(); target0.setRisklevel("III"); target0.setLocation("Combined"); Target target1 = new Target(); target1.setRisklevel("III"); target1.setLocation("Combined"); Target target2 = new Target(); target2.setRisklevel("III"); target2.setLocation("Combined"); Target target3 = new Target(); target3.setRisklevel("III"); target3.setLocation("Combined"); Target target4 = new Target(); target4.setRisklevel("IV"); target4.setLocation("Combined"); Target target5 = new Target(); target5.setRisklevel("IV"); target5.setLocation("Combined"); Target target6 = new Target(); target6.setRisklevel("IV"); target6.setLocation("Combined"); Target target7 = new Target(); target7.setRisklevel("II"); target7.setLocation("Domestic"); Target target8 = new Target(); target8.setRisklevel("IV"); target8.setLocation("Domestic"); Target target9 = new Target(); target9.setRisklevel("IV"); target9.setLocation("Domestic"); Target target10 = new Target(); target10.setRisklevel("IV"); target10.setLocation("Domestic"); Target target11 = new Target(); target11.setRisklevel("IV"); target11.setLocation("Domestic"); ListucrtargetList = new ArrayList(); ucrtargetList.add(target0); ucrtargetList.add(target1); ucrtargetList.add(target2); ucrtargetList.add(target3); ucrtargetList.add(target4); ucrtargetList.add(target5); ucrtargetList.add(target6); ucrtargetList.add(target7); ucrtargetList.add(target8); ucrtargetList.add(target9); ucrtargetList.add(target10); ucrtargetList.add(target11); List fullList = new ArrayList(); > > 

Here condition is RiskLevel and Location has to be same in each list in the list of List. So fullList should have 4 lists within it(1st III & Combined, 2nd IV & Combined, 3rd II & Domestic, 4th IV & Domestic). I could loop through the list and set the values. Is there an easier way to do this with java8 or apache commons ?

Источник

sort and group a java collection

I have an object which has a name and a score. I would like to sort a collection of such objects so that they are grouped by name and sorted by maximum score in each group (and within the group by descending score as well). let me demonstrate what I intend to achieve. assume I have these objects(name, score): (a, 3)
(a, 9)
(b, 7)
(b, 10)
(c, 8)
(c, 3) then I would like them to be sorted like this: (b, 10)
(b, 7)
(a, 9)
(a, 3)
(c, 8)
(c, 3) is this feasible with a Comparator? I can’t figure it out, so any hints would be appreciated.

As i understand it, you want sort of the equivalent of GROUP BY name ORDER BY MAX(score), score DESC , not ORDER BY name, score ?

5 Answers 5

No, you can’t do it with a single sort with a single Comparator .

  1. group by name
  2. sort the groups, by highest score in group
  3. Then you need to flatten the groups back to a list.

With Java 8

Edit: Since i wrote this answer, Java 8 has come out, which simplifies the problem a lot:

import java.util.*; import static java.util.Comparator.*; import static java.util.stream.Collectors.*; 
List result = records.stream() .sorted(comparingInt(Record::getScore).reversed()) .collect(groupingBy(Record::getName, LinkedHashMap::new, toList())) .values().stream() .flatMap(Collection::stream) .collect(toList()); 

First we sort by score reversed, and then we group using a LinkedHashMap , which will preserve the insertion order for the keys, so keys with higher score will come first.

Sorting first is OK if the groups are small, so the redundant compares between objects in different groups don’t hurt so much.

Also, with this method, duplicates are preserved.

Alternatively, if you don’t care about preserving duplicates, you can:

Comparator highestScoreFirst = comparingInt(Record::getScore).reversed(); List result = records.stream() .collect(groupingBy(Record::getName, toCollection(() -> new TreeSet<>(highestScoreFirst)))) .values().stream() .sorted(comparing(SortedSet::first, highestScoreFirst)) .flatMap(Collection::stream) .collect(toList()); 

Where the records are grouped into sorted TreeSet s, instead of sorting the values as the first operation of the stream, and then the sets are sorted by their first, highest value.

Grouping before sorting is appropriate if the groups are big, to cut down on redundant compares.

Implementing Comparable :

And you can make it shorter by having your record implement Comparable

public class Record implements Comparable  < @Override public int compareTo(Record other) < // Highest first return -Integer.compare(getScore(), other.getScore()); /* Or equivalently: return Integer.compare(other.getScore(), getScore()); */ >. > 
List result = records.stream() .collect(groupingBy(Record::getName, toCollection(TreeSet::new))) .values().stream() .sorted(comparing(SortedSet::first)) .flatMap(Collection::stream) .collect(toList()); 

Before Java 8

Edit: Here is a really rough unit test that demonstrates one way to do it. I haven’t cleaned it up as much as i would have liked.

Stuff like this is painful in Java, and i would normally use Google Guava for this.

import org.junit.Test; import java.util.*; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; public class GroupSortTest < @Test public void testGroupSort() < Listrecords = asList( new Record("a", 3), new Record("a", 9), new Record("b", 7), new Record("b", 10), new Record("c", 8), new Record("c", 3)); List> recordsGroupedByName = groupRecordsByNameAndSortedByScoreDescending(records); Collections.sort(recordsGroupedByName, byHighestScoreInGroupDescending()); List result = flattenGroups(recordsGroupedByName); List expected = asList( new Record("b", 10), new Record("b", 7), new Record("a", 9), new Record("a", 3), new Record("c", 8), new Record("c", 3)); assertEquals(expected, result); > private List flattenGroups(List> recordGroups) < Listresult = new ArrayList(); for (SortedMap group : recordGroups) < result.addAll(group.values()); >return result; > private List> groupRecordsByNameAndSortedByScoreDescending(List records) < Map groupsByName = new HashMap(); for (Record record : records) < SortedMapgroup = groupsByName.get(record.getName()); if (null == group) < group = new TreeMap(descending()); groupsByName.put(record.getName(), group); > group.put(record.getScore(), record); > return new ArrayList>(groupsByName.values()); > private DescendingSortComparator descending() < return new DescendingSortComparator(); >private ByFirstKeyDescending byHighestScoreInGroupDescending() < return new ByFirstKeyDescending(); >private static class ByFirstKeyDescending implements Comparator> < public int compare(SortedMapo1, SortedMap o2) < return o2.firstKey().compareTo(o1.firstKey()); >> private static class DescendingSortComparator implements Comparator  < public int compare(Comparable o1, Comparable o2) < return o2.compareTo(o1); >> > 

Источник

Читайте также:  Html css logo png
Оцените статью