且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

将列表中的元素分组成子列表(可能使用番石榴)

更新时间:2023-02-17 18:07:44

当然,这是可能的,甚至更容易与番石榴:)使用 Multimaps.index(Iterable,Function)

  ImmutableListMultimap&lt ; E,E> indexed = Multimaps.index(list,groupFunction); 

如果您给出具体的用例,将会更容易展示它的实际应用。



来自文档的示例:

  List< String> badGuys = 
Arrays.asList(Inky,Blinky,Pinky,Pinky,Clyde);
函数< String,Integer> stringLengthFunction = ...;
Multimap< Integer,String> index =
Multimaps.index(badGuys,stringLengthFunction);
System.out.println(index);

打印

  {4 = [Inky],6 = [Blinky],5 = [Pinky,Pinky,Clyde]} 

在你的情况下,如果GroupFunction定义为:

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


然后它会转化为:

 函数< String,Integer> stringLengthFunction = new Function< String,Integer>(){
@Override public Integer apply(final String s){
return s.length();






$ b

可能 stringLengthFunction 在Guava示例中使用的实现。






最后,在Java 8中,整个代码段可能更简单,因为lambas和方法引用足够简洁,可以内联:

  ImmutableListMultimap< E,E> indexed = Multimaps.index(list,String :: length); 

对于使用 Collector.groupingBy ,请参阅 Jeffrey Bosboom的回答,但这种方法几乎没有区别:它不返回 ImmutableListMultimap ,而是 Map code>与集合值,


  • 返回Map的类型,可变性,可串行性或线程安全性 source ),



  • 它比Guava +方法引用稍微冗长一些。






  • 编辑:如果您不关心索引键,您可以获取分组值: / p>

     列表<列表< E>>分组= list.transform(indexed.keySet()。asList(),new Function< E,List< E>>(){
    @Override public List< E> apply(E key){
    return indexed.get(key);
    }
    });

    //或相同的视图,但使用Java 8 lambda表达式:
    List< List< E>> groupped = Lists.transform(indexed.keySet()。asList(),indexed :: get);

    什么给你列表<列表< E>> 查看哪些内容可以很容易地复制到 ArrayList 中,或者按照原样使用,就像您想要的那样。还要注意 indexed.get(key) ImmutableList




    List< List< E>>< code> groupped = indexed.keySet()。stream()
    .map(indexed :: get)
    .collect(Collectors.toList());

    编辑2 :正如Petr Gladkikh提到 Collection< List< E>> 就足够了,上面的例子可能会更简单:

     收集和LT;列表与LT E  - 代替;&GT; groupped = indexed.asMap()。values(); 


    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();