【问题标题】:Reversing a Queue<Integer> and converting it into an int array反转 Queue<Integer> 并将其转换为 int 数组
【发布时间】:2019-05-30 14:46:17
【问题描述】:

我有一个Queue&lt;Integer&gt; 声明为Queue&lt;Integer&gt; queue=new LinkedList();,我需要反转其中的元素顺序,然后将其转换为一个int 数组。我写了下面的代码:

Collections.reverse((List)queue);
int[] res=queue.stream().mapToInt(Integer::intValue).toArray();

这段代码有两个问题:

  1. 显式转换(List)queue;
  2. 我想知道是否有单线解决方案。

那么我们有没有更优雅的方式来做到这一点?


问题的澄清:

队列是否颠倒并不重要。我需要一个反转元素的 int 数组。

【问题讨论】:

    标签: java collections queue


    【解决方案1】:

    首先,不要使用原始类型(使用菱形运算符)。不完全是一个班轮,但您可以先转换为 int[],然后使用 commons lang ArrayUtils.reverse(int[]) like

    Queue<Integer> queue = new LinkedList<>();
    // ...
    int[] arr = queue.stream().mapToInt(Integer::intValue).toArray();
    ArrayUtils.reverse(arr);
    

    您还可以编写自己的 int[] 反向方法,以实现流畅的界面(例如返回 int[]),然后您可以将其设为单行。喜欢,

    public static int[] reverse(int[] arr) {
        for (int i = 0; i < arr.length / 2; i++) {
            int temp = arr[i];
            arr[i] = arr[arr.length - i - 1];
            arr[arr.length - i - 1] = temp;
        }
        return arr;
    }
    

    然后

    int[] arr = reverse(queue.stream().mapToInt(Integer::intValue).toArray());
    

    【讨论】:

    • 但这不会反转队列。
    • @nullpointer 真。但是,如果目标是颠倒的int[],则不清楚队列是否也必须颠倒。事实上,我会假设队列超出范围,int[] 会返回给调用者。
    【解决方案2】:

    这里不需要花哨。

    static int[] toReversedArray(Queue<Integer> queue) {
        int i = queue.size();
        int[] array = new int[i];
        for (int element : queue) {
            array[--i] = element;
        }
        return array;
    }
    

    不是单行的,但易于阅读且速度快。

    【讨论】:

      【解决方案3】:

      Collections.reverse 仅暗示List,这只是Collection 的一种类型,您不能将Queue 转换为List。但您可以尝试将其转换为 LinkedList 为:

      Collections.reverse((LinkedList)queue);
      

      详情

      我怀疑是否有用于反转队列的内置 API。您仍然可以使用Stack 作为常规方式:

      Stack<Integer> stack = new Stack<>();
      while (!queue.isEmpty()) {
          stack.add(queue.remove());
      }
      while (!stack.isEmpty()) {
          queue.add(stack.pop());
      }
      

      然后根据需要转换为数组

      int[] res = queue.stream().mapToInt(Integer::intValue).toArray();
      

      另一方面,如果 Deque 目前满足您的需求,您可以简单地依赖 LinkedList 本身,因为它也实现了 Deque。那么您当前的实现将非常简单:

      LinkedList<Integer> dequeue = new LinkedList<>();
      Collections.reverse(dequeue);
      int[] res = dequeue.stream().mapToInt(Integer::intValue).toArray();
      

      队列是否颠倒并不重要。一个 int 数组 颠倒的元素是我需要的。

      其他人已经建议的另一种解决方案是将Streamqueue 反转,然后将mapToInt 转换为数组:

      Queue<Integer> queue = new LinkedList<>();
      int[] res = reverse(queue.stream()).mapToInt(Integer::intValue).toArray();
      

      这使用了 Stuart Marks in this answer 建议的实用程序 reverse,这样:

      @SuppressWarnings("unchecked")
      static <T> Stream<T> reverse(Stream<T> input) {
          Object[] temp = input.toArray();
          return (Stream<T>) IntStream.range(0, temp.length)
                  .mapToObj(i -> temp[temp.length - i - 1]);
      }
      

      【讨论】:

      • 您可能不应该使用Stack 类,因为它扩展了Vector,因此是同步的,这里不需要,只会降低性能。
      • 如果使用Deque,则使用Deque.descendingIterator() 结合SpliteratorsStreamSupport 可能更有效,假设只需要反转数组而不需要反转Deque。不过,代码会更冗长。
      • @Slaw 可以肯定。只是我写答案的目的是确保原始存储被反转,但后来 OP 澄清说,反转的输出最终才是最重要的。
      • @Marcono1234 实际上,当 JVM 检测到它们没有被共享并且它们的获取成本可以忽略不计时,它会删除 Vector 类中的 synchronized 块是它的最新版本:)但是,是的,原则上你不应该这样做,因为不建议再使用Vector
      【解决方案4】:

      Java8 版本中,您可以使用 Stream API 来帮助您。

      这样的代码骨架:

      int[] reversedQueue = queue.stream()
          .collect(Collector.of(() -> new ArrayDeque<Integer>(), ArrayDeque::addFirst, (a,b)->a))
          .stream().mapToInt(Integer::intValue).toArray();
      

      【讨论】:

      • 结果中您的组合器 ((a,b)-&gt;a) 似乎缺少 b
      • @Marcono1234 没问题。Collector.of方法的第三个参数是一个BinaryOperator,它是新收集器的combiner函数。在我们的代码中只有一个收集器,所以不能错过收集器中的任何元素。
      • 在这种情况下可能没有关系,因为(如果我理解正确的话)组合器仅用于并行流。但是,您可能应该评论该实现不正确,以防止将来出现错误,以防有人将此代码用于并行流。应该是(a, b) -&gt; {b.addAll(a); return b;}
      【解决方案5】:

      您可以使用Eclipse Collections 中的LazyIterate 实用程序,如下所示。

      int[] res = LazyIterate.adapt(queue)
              .collectInt(i -> i)
              .toList()
              .asReversed()
              .toArray();
      

      您还可以将 Collectors2 类与 Java 流一起使用。

      int[] ints = queue.stream()
              .collect(Collectors2.collectInt(i -> i, IntLists.mutable::empty))
              .asReversed()
              .toArray();
      

      您可以将int 值直接流式传输到MutableIntList,将其反转,然后将其转换为int 数组。

      int[] ints =
          IntLists.mutable.ofAll(queue.stream().mapToInt(i -> i)).asReversed().toArray();
      

      最后,您可以将int 值直接流式传输到MutableIntStack 并将其转换为int 数组。

      int[] ints =
          IntStacks.mutable.ofAll(queue.stream().mapToInt(i -> i)).toArray();
      

      注意:我是 Eclipse Collections 的提交者。

      【讨论】:

        【解决方案6】:

        最后,我想出了这一行的解决方案。

        Integer[] intArray = queue.stream()
                    .collect(LinkedList::new, LinkedList::addFirst, LinkedList::addAll)
                    .toArray(new Integer[queue.size()]);
        

        int[] 版本应该喜欢

        int[] intArray = queue.stream()
                    .collect(LinkedList<Integer>::new, LinkedList::addFirst, LinkedList::addAll)
                    .stream()
                    .mapToInt(Integer::intValue)
                    .toArray();
        

        【讨论】:

          【解决方案7】:

          这是一行,但可能效率不高:

          int[] res = queue.stream()
                           .collect(LinkedList<Integer>::new, (l, e) -> l.addFirst(e), (l1, l2) -> l1.addAll(l2))
                           .stream()
                           .mapToInt(Integer::intValue)
                           .toArray();
          

          如果你想变得高效和可读,你应该继续使用你现在拥有的东西。

          【讨论】:

          • 这不会反转队列(或其值)
          【解决方案8】:

          这是在一行代码中使用StreamCollections.reverse() 的不同解决方案:

          Integer[] reversedArray = queue.stream()
                  .collect(Collectors.collectingAndThen(Collectors.toList(),
                          list -> {
                              Collections.reverse(list);
                              return list.toArray(new Integer[0]);
                          }
                  ));
          

          int[] reversedArray = queue.stream()
                  .collect(Collectors.collectingAndThen(Collectors.toList(),
                          list -> {
                              Collections.reverse(list);
                              return list.stream()
                                      .mapToInt(Integer::intValue)
                                      .toArray();
                          }
                  ));
          

          【讨论】:

            【解决方案9】:

            这是一种无需反转队列即可创建反转数组的方法:

            int[] i = { queue.size() };
            int[] array = new int[i[0]];
            queue.forEach(n -> array[--i[0]] = n);
            

            由于无法从 lambda 表达式中修改局部变量,上述代码非常麻烦。所以这里i需要是一个单元素数组,才能克服这个限制。

            注意:请记住,我来这个解决方案只是为了好玩:)

            【讨论】:

              猜你喜欢
              • 2013-07-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-12-26
              • 1970-01-01
              • 2015-10-02
              相关资源
              最近更新 更多