Java 将列表中的元素分组为子列表(可能使用guava)
我想对列表中的元素进行分组。我现在是这样做的:Java 将列表中的元素分组为子列表(可能使用guava),java,list,function,grouping,guava,Java,List,Function,Grouping,Guava,我想对列表中的元素进行分组。我现在是这样做的: 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) {
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);
}
公共静态列表组(最终列表列表,最终组函数GroupFunction){
列表结果=Lists.newArrayList();
对于(最终E元素:列表){
布尔groupFound=false;
对于(最终列表组:结果){
if(groupFunction.sameGroup(元素,group.get(0))){
组。添加(元素);
groupFound=true;
打破
}
}
如果(!groupFound){
List newGroup=Lists.newArrayList();
添加(元素);
结果。添加(新组);
}
}
返回结果;
}
公共接口组函数{
公共布尔sameGroup(最终E元素1,最终E元素2);
}
有没有更好的方法来做到这一点,最好是用番石榴?当然有可能,用番石榴更容易:)使用: 在您的情况下,如果GroupFunction定义为:
GroupFunction<String> groupFunction = new GroupFunction<String>() {
@Override public String sameGroup(final String s1, final String s2) {
return s1.length().equals(s2.length());
}
}
对于使用see的纯Java 8(无番石榴)示例,尽管该方法几乎没有区别:
- 它不返回
,而是返回带有ImmutableListMultimap
值的Collection
Map
- 无法保证返回的映射()的类型、可变性、序列化性或线程安全性
- 它比Guava+方法参考更详细
编辑:如果不关心索引键,可以获取分组值:
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);
编辑2:正如Petr Gladkikh提到的,如果收集足够,上述示例可能更简单:
Collection<List<E>> grouped = indexed.asMap().values();
Collection group=index.asMap().values();
最简单的方法是使用:
上述示例可以重新编写:
List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Group group = group(badGuys, by(on(String.class).length)));
System.out.println(group.keySet());
List badGuys=Arrays.asList(“Inky”、“Blinky”、“Pinky”、“Pinky”、“Clyde”);
组=组(坏人,由(on(String.class.length));
System.out.println(group.keySet());
Java 8 streams库中的提供了与Guava的Multimaps.index
相同的功能。以下是中的示例,重写为使用Java 8流:
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);
如果要以创建列表以外的其他方式将值与同一个键组合,可以使用另一个收集器的groupingBy
重载。此示例使用分隔符连接字符串:
Map<Integer, String> index = badGuys.stream()
.collect(Collectors.groupingBy(String::length, Collectors.joining(" and ")));
如果您有一个大的列表,或者您的分组函数很昂贵,那么您可以使用parallelStream
和并发收集器进行并行处理
Map<Integer, List<String>> index = badGuys.parallelStream()
.collect(Collectors.groupingByConcurrent(String::length));
使用Java8、Guava和少数几个助手函数,您可以使用自定义比较器实现分组
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);
}
公共静态映射组(列表项、比较器)
{
ListMultimap blocks=LinkedListMultimap.create();
如果(!ArrayUtils.isNullOrEmpty(项目))
{
T currentItem=null;
对于(T项:项)
{
如果(currentItem==null | |比较器。比较(currentItem,item)!=0)
{
当前项目=项目;
}
blocks.put(currentItem,ObjectUtils.clone(item));
}
}
返回Multimaps.asMap(块);
}
范例
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);
});
Comparator Comparator=Comparator.comparingit(SportExercise::getEstimatedTime)
。然后比较它(SportExecute::getActiveTime)。然后比较它(SportExecute::getIntervalCount)
.Then比较长(SportExercise::getExerciseId);
图块=组(sportWorkout.GetTrainingExcessions(),比较程序);
blocks.forEach((键、值)->{
系统输出打印项次(键);
System.out.println(值);
});
这正是设计多重映射的目的。代替上一个代码示例索引。asMap().values()
可能足以获得集合
感谢这非常有用,例如,如何基于多个标准进行分组,假设您在函数中接收到一个包含两个字段的对象,并且您需要按此字段分组,我该如何做?java 7和8如何使用字符串作为番石榴分组的索引?@Alex78191您的确切意思是什么?似乎是一个单独的问题。对于多级分组,您可以按属性值列表进行分组。
List<String> badGuys = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
Group group = group(badGuys, by(on(String.class).length)));
System.out.println(group.keySet());
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);
{4=[Inky], 5=[Pinky, Pinky, Clyde], 6=[Blinky]}
Map<Integer, String> index = badGuys.stream()
.collect(Collectors.groupingBy(String::length, Collectors.joining(" and ")));
{4=Inky, 5=Pinky and Pinky and Clyde, 6=Blinky}
Map<Integer, List<String>> index = badGuys.parallelStream()
.collect(Collectors.groupingByConcurrent(String::length));
{4=[Inky], 5=[Pinky, Clyde, Pinky], 6=[Blinky]}
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);
}
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);
});