当前位置: 首页 > 知识库问答 >
问题:

使用流在列表列表中查找对象[重复]

桂高昂
2023-03-14

我正在尝试编写一个方法,该方法可以在列表列表中找到对象的索引并利用并行性。这是我的代码。

// returns [i, j] where lists.get(i).get(j) equals o, or null if o is not present.
public static int[] indices(List<? extends List<?>> lists, Object o) {
    return IntStream.range(0, lists.size())
                    .boxed()
                    .flatMap(i -> IntStream.range(0, lists.get(i).size()).mapToObj(j -> new int[]{i, j}))
                    .parallel()
                    .filter(a -> {
                        System.out.println(Arrays.toString(a));     // For testing only
                        return Objects.equals(o, lists.get(a[0]).get(a[1]));
                    })
                    .findAny()
                    .orElse(null);
}

当我运行以下代码时

List<List<String>> lists = Arrays.asList(
        Arrays.asList("A", "B", "C"),
        Arrays.asList("D", "E", "F", "G"),
        Arrays.asList("H", "I"),
        Collections.nCopies(5, "J")
);
System.out.println("Indices are " + Arrays.toString(indices(lists, "J")));

输出类似于

[0, 0]
[0, 1]
[0, 2]
[3, 0]
[3, 1]
[3, 2]
[3, 3]
[2, 0]
[3, 4]
[1, 0]
[1, 1]
[2, 1]
[1, 2]
[1, 3]
Indices are [3, 0]

换句话说,即使在找到对象之后,搜索仍在继续。findAny不应该是短路操作吗?我错过了什么?此外,在迭代列表或锯齿数组时,利用并行性的最佳方法是什么?

编辑

按照@Sotirios回答中的想法,我得到了以下输出

Thread[ForkJoinPool.commonPool-worker-3,5,main] [3, 0]
Thread[main,5,main] [2, 0]
Thread[main,5,main] [2, 1]
Thread[ForkJoinPool.commonPool-worker-1,5,main] [1, 0]
Thread[ForkJoinPool.commonPool-worker-1,5,main] [1, 1]
Thread[ForkJoinPool.commonPool-worker-1,5,main] [1, 2]
Thread[ForkJoinPool.commonPool-worker-1,5,main] [1, 3]
Thread[main,5,main] [0, 0]
Thread[main,5,main] [0, 1]
Thread[ForkJoinPool.commonPool-worker-3,5,main] [3, 1]
Thread[main,5,main] [0, 2]
Thread[ForkJoinPool.commonPool-worker-3,5,main] [3, 2]
Thread[ForkJoinPool.commonPool-worker-3,5,main] [3, 3]
Thread[ForkJoinPool.commonPool-worker-3,5,main] [3, 4]
Indices are [3, 0]

请注意

Thread[ForkJoinPool.commonPool-worker-3,5,main]

即使找到答案也继续搜索。

共有3个答案

孙化
2023-03-14
匿名用户

这并不是说它继续,而是它已经调度了各种线程来尝试找到结果,并将等到这些线程完成后再返回结果。

换句话说,< code>findAny终端操作将把“搜索”任务提交给许多线程。这些任务只是应用< code>filter 谓词并在返回< code>true时返回。< code>findAny,大概是等待其中一个返回值。它没有办法真正取消它已经提交的任何东西,而且看起来这个实现将会阻塞,直到整个批处理返回。它只能停止提交任何未来批次。

您可以通过记录当前线程来验证这一点:

System.out.println(Thread.currentThread() + " " + Arrays.toString(a)); // For testing only

尉迟雅昶
2023-03-14

至于“为什么会这样实现”。问题深深地在于Stream API实现。平地图主体经常创建一个带有一些中间操作的流(如.平地图(list-

尚嘉庆
2023-03-14

短路操作不能保证只拉动产生其结果所需的少量元件。他们可以这样做,但不是必须的。

flatMap 的当前实现使得它始终将子流的全部内容推送到下游。因此,即使您的流不是并行的,您也可以看到流中流的元素比满足 findAny 所需的元素多。

 类似资料:
  • 我正在使用MongoDB搜索包含列表列表的元素,其中列表中至少有一个项目与搜索参数匹配。 这是我目前拥有的结构的一个例子。 我想搜索数据列表中值为“绿色”的所有项目。 我目前有这个: 但是,不会返回任何结果。

  • 我有两个类的结构如下: 基本上,Company类有一个Person对象列表,每个Person对象都可以获得一个标记值。 如果我得到Person对象的列表,有没有一种方法可以使用Java8中的Stream来查找所有Person对象中最常见的一个标记值(如果是并列的,可能只是最常见的一个随机标记)?

  • 我无法解决这个问题。 我想用Java流来解决这个问题: 有什么解决办法吗?谢谢!

  • 我有超过15个字符串列表,每个列表包含几个不同的代码。每个列表包含一种特定类型的代码。我有一个输入代码,必须找出该输入代码属于哪个列表,并根据结果返回一个特定字符串。我用if,else if来做这个。下面是示例代码 每个列表如下所示:公共静态列表codeTypeOneList=新ArrayList(); (其他代码类型的类似列表) 有没有更好的方法来实现这一点?谢谢

  • 我有一个清单,必须找到具体的对象。我必须按学生平均价值排序列表,并创建函数来搜索具有第二高价值的学生。如果与其他学生重复,则按函数返回较小的学生。这个任务的另一个要求(要妥善解决)是我不能创建任何对象。下面我留下了我正在使用的类的代码: 现在,我尝试通过对stream进行反向排序来解决这个问题,然后移除stream的第一个值,并比较stream的两个下一个对象并返回正确的一个。我可以使用for循环

  • 假设我有一个名为House的对象,它包含一个列表 对于房间,只有一个属性,其值由int表示: 现在,使用Java8,并给出一个带有