当前位置: 首页 > 面试题库 >

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

那正初
2023-03-14
问题内容

我想对列表中的元素进行分组。我目前正在这样做:

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

是否有更好的方法来做到这一点,最好使用番石榴?


问题答案:

当然可以,并且使用Guava甚至更容易:)使用Multimaps.index(Iterable, Function)

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

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

来自文档的示例:

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

版画

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

那么它将转换为:

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

这是stringLengthFunctionGuava示例中可能使用的实现。

最后,在Java 8中,整个片段甚至可以变得更加简单,因为lambas和方法引用足够简洁,可以内联:

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

对于使用纯Java
8(无Guava)的示例,Collector.groupingBy请参见[JeffreyBosboom的答案],尽管该方法几乎没有区别:

  • 它不会返回ImmutableListMultimap,而是Map带有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);

首先,您Lists<List<E>>可以根据需要查看哪些内容可以轻松复制ArrayList或按原样使用。还要注意的indexed.get(key)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());

编辑2 :正如Petr Gladkikh在下面的评论中提到的,如果Collection<List<E>>足够的话,上面的示例可能会更简单:

Collection<List<E>> grouped = indexed.asMap().values();


 类似资料:
  • 问题内容: 我有这个清单(): 我想要这样的东西: 换句话说,我想使用值作为分隔符将列表拆分为子列表,以获得列表列表()。我正在寻找Java 8解决方案。我已经尝试过,但是我不确定这是我要找的东西。谢谢! 问题答案: 我目前想出的唯一解决方案是实现自己的自定义收集器。 在阅读解决方案之前,我想添加一些有关此的注释。我将这个问题更多地当作编程练习,我不确定是否可以使用并行流来完成。 因此,您必须意识

  • 问题内容: 假设我们有一个项目集合: 我想从Guava库(该列表为Ordering,我想)中从列表中获得最高价格的商品。我的意思类似于此Groovy代码: 我怎么做?有效率吗? 问题答案: 它的效率是最高的:遍历列表中的项目,并返回价格最高的第一个Item:O(n)。

  • 问题内容: 我有大量的这种格式的元组列表。每个元组的第二个字段是类别字段。 将其分解为相同类别(A,B,C等)的子列表的最有效方法是什么? 问题答案: 使用itertools.groupby: 产量 或者,要创建一个将每个组作为子列表的列表,可以使用列表理解: to的第二个参数是一个适用于(第一个参数)中每个项目的函数。预期会传回。然后将相同的所有连续项目组合在一起。 operator.itemg

  • 问题:如何将列表拆分为两个子列表,其中元素由元素中的选项卡分隔? 上下文:我想读取一个由制表符分隔的文件到Pandas DataFrame中。这些文件看起来像: 列1\t 123 列2\t 列3\t文本 这意味着每行有一列,后面跟着一个选项卡,然后是该列的一个值(有时没有值)。 我的想法是读取文件并将每行保存为列表的元素,然后将列表分成两个,将选项卡前的第一部分作为一个列表,选项卡后的第二部分作为

  • 问题内容: 我已经编写了此函数,用于将元组列表转换为列表列表。有没有更优雅的/ Pythonic的方式来做到这一点? 问题答案: 您可以使用列表推导:

  • 我甚至不确定这是否可能,但我正在执行一个集合操作,如或,我需要将其转换为以便洗牌列表并将其传递给接受而不是的其他方法。因此,我将结果转换为并且一切都很好。但是从探查器中,我看到操作在负载下花费了很长时间,这是因为Guava设置的方式。它不像普通java集那样是一个常量操作。 下面是代码示例 我正在尝试找到将番石榴转换为的最快方法。通过挖掘代码,这就是Guava Sets所做的工作https://g