【问题标题】:How to convert List<Integer> to int[] in Java? [duplicate]如何在 Java 中将 List<Integer> 转换为 int[]? [复制]
【发布时间】:2010-10-31 22:03:26
【问题描述】:

这类似于这个问题: How to convert int[] to Integer[] in Java?

我是 Java 新手。如何在 Java 中将 List&lt;Integer&gt; 转换为 int[]?我很困惑,因为List.toArray() 实际上返回了一个Object[],它可以转换为下界Integer[]int[]

现在我正在使用循环来执行此操作:

int[] toIntArray(List<Integer> list){
  int[] ret = new int[list.size()];
  for(int i = 0;i < ret.length;i++)
    ret[i] = list.get(i);
  return ret;
}

我确信有更好的方法来做到这一点。

【问题讨论】:

  • 您只能使用以下方法转换为 Integer[]:Integer[] arr = (Integer[])list.toArray(new Integer[list.size]);
  • @Hardcoded 您可能想编辑您的评论以使用 list.size() 方法并删除不必要的演员表。
  • 现在在 Java 8 中有没有更好的方法来做到这一点?
  • (@Makoto : 见Pshemo's answer)
  • int[] arr = listOfIntegers.stream().mapToInt(x->x).toArray();

标签: java arrays collections


【解决方案1】:

还没有人提到 Java 8 中添加了流,所以就这样吧:

int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();

思考过程:

  • 简单的Stream#toArray 返回一个Object[] 数组,所以它不是我们想要的。另外,Stream#toArray(IntFunction&lt;A[]&gt; generator) 没有做我们想做的事情,因为泛型类型 A 不能代表原始类型 int

  • 所以最好有一些流可以处理原始类型int 而不是包装器Integer,因为它的toArray 方法很可能还会返回一个int[] 数组(返回类似Object[] 甚至盒装 Integer[] 在这里都是不自然的)。幸运的是,Java 8 有这样一个流 IntStream

  • 所以现在我们唯一需要弄清楚的是如何将我们的Stream&lt;Integer&gt;(将从list.stream() 返回)转换为闪亮的IntStream。这里Stream#mapToInt(ToIntFunction&lt;? super T&gt; mapper) 方法来救援。我们需要做的就是传递一个从Integerint 的映射。

    我们可以使用类似Integer#intValue 的东西,它返回一个int,如下所示:

    mapToInt( (Integer i) -> i.intValue() )  
    

    (或者有些人可能更喜欢:mapToInt(Integer::intValue)。)

    但是可以使用拆箱生成类似的代码,因为编译器知道这个 lambda 的结果必须是 int 类型(mapToInt 中使用的 lambda 是 ToIntFunction 接口的实现,它期望作为主体一个方法类型:int applyAsInt(T value),预计返回一个int)。

    所以我们可以简单地写:

    mapToInt((Integer i)->i)
    

    另外,由于(Integer i) 中的Integer 类型可以由编译器推断,因为List&lt;Integer&gt;#stream() 返回一个Stream&lt;Integer&gt;,我们也可以跳过它,这让我们有了

    mapToInt(i -> i)
    

【讨论】:

  • 显然是最好的解决方案。太糟糕了,它缺乏解释。
  • @PimpTrizkit 稍微更新了这个答案。希望现在更清楚了。
  • @Pshemo - 谢谢!我个人不需要解释。但我讨厌看到没有一个完美的答案!无论如何,您的解释确实教育了我并且很有帮助。我想知道为什么 mapTo... 函数不允许 null lambda .... 像 sort 那样......这使它默认为默认行为......在这种情况下,i -&gt; i 将是一个完美的选择默认行为。
  • 我猜这个答案比 ColinD 使用 Guava 的答案要快,对吧?
  • @vefthym 我没有测试它,但我怀疑这两种解决方案的工作原理相同,所以我希望速度相似(但可以随意对其进行基准测试)。这个答案的一个优点是,只要我们有 Java 8,它就不需要额外的库。
【解决方案2】:

不幸的是,由于 Java 处理原始类型、装箱、数组和泛型的性质,我不认为真的有更好的方法来做到这一点。特别是:

  • List&lt;T&gt;.toArray 不起作用,因为没有从 Integerint 的转换
  • 您不能将int 用作泛型的类型参数,因此它必须 成为int 特定的方法(或使用反射来做恶作剧的方法)。

我相信有些库为所有原始类型自动生成了这种方法的版本(即,有一个为每种类型复制的模板)。这很丑陋,但恐怕就是这样:(

即使 Arrays 类在泛型进入 Java 之前就已经出现,但如果它在今天被引入,它仍然必须包含所有可怕的重载(假设你想使用原始数组)。

【讨论】:

  • 另见 ColinD 关于番石榴的 Ints.toArray(Collection) 的回答
  • @JonSkeet 你的意思是像binarySearchcopyOfcopyOfRange...的 Arrays 类中已经存在的可怕重载?我想知道为什么他们不能添加另一组可怕的重载。
  • @ron ColinD 的回答除了 OP 已经拥有的东西之外没有给出任何东西 - for 循环用非原始数组填充原始数组。
  • 与此同时,在 Oracle 的 Java 工程师们正专注于使用模块使语言过于复杂......
  • @bvdb:我是说没有其他库(基本上仍然有循环,但在他们的代码中不是你的),我不相信有更好的方法。这比说我不知道​​是否有更好的方法要强得多。
【解决方案3】:

除了Commons Lang,你可以用Guava的方法Ints.toArray(Collection&lt;Integer&gt; collection)来做到这一点:

List<Integer> list = ...
int[] ints = Ints.toArray(list);

这使您不必进行 Commons Lang 等效项需要您自己进行的中间数组转换。

【讨论】:

  • 不幸的是,中间数组隐藏在 Guava 内部:Object[] boxedArray = collection.toArray();
  • "还好中间数组隐藏在 Guava 内部。" - 为你解决了这个问题。 ;)
【解决方案4】:

最简单的方法是使用Apache Commons Lang。它有一个方便的 ArrayUtils 类,可以做你想做的事。使用 toPrimitive 方法和 Integers 数组的重载。

List<Integer> myList;
 ... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));

这样您就不会重新发明轮子。 Commons Lang 有很多 Java 遗漏的有用的东西。上面,我选择创建一个大小合适的整数列表。也可以使用长度为 0 的静态 Integer 数组,让 Java 分配一个大小合适的数组:

static final Integer[] NO_INTS = new Integer[0];
   ....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));

【讨论】:

  • toPrimitive 链接已损坏。
  • 这里是 2.6 Commons Lang API 的链接:toPrimitive
  • 请注意,这将需要 2 个分配和副本:myList.toArray() 将创建一个 Integer[] 并填充它,而 ArrayUtils.toPrimitive() 将分配一个 int[] 并取消框输入。
【解决方案5】:

Java 8 为我们提供了一种通过流实现此目的的简单方法...

使用集合stream() 函数然后映射到整数,您将获得一个IntStream。使用IntStream,我们可以调用toArray(),它给了我们int []

int [] ints = list.stream().mapToInt(Integer::intValue).toArray();

to int []

to IntStream

【讨论】:

    【解决方案6】:
    int[] toIntArray(List<Integer> list)  {
        int[] ret = new int[list.size()];
        int i = 0;
        for (Integer e : list)  
            ret[i++] = e;
        return ret;
    }
    

    对代码稍作更改以避免昂贵的列表索引(因为列表不一定是 ArrayList,但可能是链表,随机访问的成本很高)

    【讨论】:

    • 我不明白:在数组中查找元素并不慢。它在 O 中运行,其中 n 是数组的大小,即它完全不依赖于数组的大小或任何东西。在 C 中: myarray[c] 与: myarray + c * sizeof(myarray[0] ) ... 运行速度 very 相同。
    • 该方法以List为参数,并非所有实现都具有快速随机访问(如ArrayList)
    • @Hugh:区别不在于如何访问数组,而在于如何访问List。 list.get(i) 为每次访问执行边界检查和填充。我不知道新的解决方案是否真的更好,但至少迈克是这么说的,也许是这样。编辑:我忘记了Java允许索引到一个链表(我习惯了C++的std::list,它不允许它)。所以 arjantop 关于非 ArrayList 的说法也是正确的;即使没有边界检查,索引也不一定很快。
    • @Lajnold 在现代 JIT 中,ArrayList 的边界检查是免费的。但是,如果 Java 更多地遵循 STL 并且只实现真正有意义的方法,我更愿意(LinkedList::get(int) 没有,因为它可能会很慢)。
    • @maaartinus 接口的全部目的是将实现与接口分离。如果您了解基本思想,那么在 Java 中解决它的方式就很有意义。 Here 是关于它的一些信息。
    【解决方案7】:

    这是 Java 8 的单行代码

    public int[] toIntArray(List<Integer> intList){
           return intList.stream().mapToInt(Integer::intValue).toArray();
    }
    

    【讨论】:

      【解决方案8】:

      如果您只是将Integer 映射到int,那么您应该考虑using parallelism,因为您的映射逻辑不依赖于其范围之外的任何变量。

      int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();
      

      请注意这一点

      请注意,并行性并不会自动比串行执行操作更快,尽管如果您有足够的数据和处理器内核,它可能会更快。虽然聚合操作使您能够更轻松地实现并行性,但您仍然有责任确定您的应用程序是否适合并行性。


      有两种方法可以将整数映射到它们的原始形式:

      1. 通过ToIntFunction

        mapToInt(Integer::intValue)
        
      2. 通过带有 lambda 表达式的显式 unboxing

        mapToInt(i -> i.intValue())
        
      3. 通过使用 lambda 表达式的隐式(自动)拆箱。

        mapToInt(i -> i)
        

      给定一个带有null 值的列表

      List<Integer> list = Arrays.asList(1, 2, null, 4, 5);
      

      这里有三个处理null的选项:

      1. 在映射之前过滤掉null 值。

        int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
        
      2. null 值映射到默认值。

        int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
        
      3. 在 lambda 表达式中处理 null

        int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
        

      【讨论】:

      • 请注意,mapToInt(Integer::intValue)mapToInt(i -&gt; i.intValue()) 完全相同(表达完全相同的方法调用的两种方式),并且所有三个实际上都是相同的(相同的字节码)。
      • 这太棒了,谢谢分享!
      【解决方案9】:

      这个简单的循环总是正确的!没有错误

        int[] integers = new int[myList.size()];
        for (int i = 0; i < integers.length; i++) {
            integers[i] = myList.get(i);
        }
      

      【讨论】:

      • “有效”不等于“理想”,性能问题可以认为是bug。 List#get(int) 不能保证是一个恒定时间的操作,正如您可能已经假设的那样,所以它不应该用于迭代。相反,请使用专为此用例设计的迭代器。使用 Java 5+ foreach 循环或调用 List#iterator() 并使用迭代器。此外,列表的大小可能会在此循环期间发生变化,从而导致 IndexOutOfBoundsException 或不完整的数组。许多迭代器实现都有详细记录的策略来处理这种情况。
      • 比狗吃的Java流好多了
      【解决方案10】:

      我会在这里再扔一个。我注意到 for 循环的几种用途,但您甚至不需要循环内的任何东西。我提到这一点只是因为最初的问题是试图找到不那么冗长的代码。

      int[] toArray(List<Integer> list) {
          int[] ret = new int[ list.size() ];
          int i = 0;
          for( Iterator<Integer> it = list.iterator(); 
               it.hasNext(); 
               ret[i++] = it.next() );
          return ret;
      }
      

      如果 Java 允许像 C++ 那样在 for 循环中声明多个声明,我们可以更进一步,执行 for(int i = 0, Iterator it...

      虽然最后(这部分只是我的观点),如果你打算有一个帮助功能或方法为你做某事,只需设置它并忘记它。它可以是单行或十行;如果你再也看不到它,你就不会知道其中的区别。

      【讨论】:

        【解决方案11】:

        实际上没有办法“单线”你正在尝试做的事情,因为 toArray 返回一个 Object[] 并且你不能从 Object[] 转换为 int[] 或 Integer[] 转换为 int[]

        【讨论】:

        • 由于数组协方差,您可以在 Object[] 和 Integer[] 之间转换 - 但不能在 int[] 和 Integer[] 之间转换。
        • 感谢您的纠正,我将编辑我的答案以反映您所说的内容。
        【解决方案12】:
        int[] ret = new int[list.size()];       
        Iterator<Integer> iter = list.iterator();
        for (int i=0; iter.hasNext(); i++) {       
            ret[i] = iter.next();                
        }                                        
        return ret;                              
        

        【讨论】:

          【解决方案13】:

          也可以试试Dollar (check this revision):

          import static com.humaorie.dollar.Dollar.*
          ...
          
          List<Integer> source = ...;
          int[] ints = $(source).convert().toIntArray();
          

          【讨论】:

            【解决方案14】:

            我建议您使用 java 集合 API 中的 List&lt;?&gt; skeletal 实现,它在这种特殊情况下似乎很有帮助:

            package mypackage;
            
            import java.util.AbstractList;
            import java.util.Arrays;
            import java.util.Collections;
            import java.util.List;
            
            public class Test {
            
            //Helper method to convert int arrays into Lists
            static List<Integer> intArrayAsList(final int[] a) {
                if(a == null)
                    throw new NullPointerException();
                return new AbstractList<Integer>() {
            
                    @Override
                    public Integer get(int i) {
                        return a[i];//autoboxing
                    }
                    @Override
                    public Integer set(int i, Integer val) {
                        final int old = a[i];
                        a[i] = val;//auto-unboxing
                        return old;//autoboxing
                    }
                    @Override
                    public int size() {
                        return a.length;
                    }
                };
            }
            
            public static void main(final String[] args) {
                int[] a = {1, 2, 3, 4, 5};
                Collections.reverse(intArrayAsList(a));
                System.out.println(Arrays.toString(a));
            }
            }
            

            注意装箱/拆箱的缺点

            【讨论】:

            • 这没有回答 OP 的问题——OP 询问了如何从 List 转换为数组。
            【解决方案15】:

            使用Eclipse Collections,如果您有java.util.List&lt;Integer&gt; 类型的列表,您可以执行以下操作:

            List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
            int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();
            
            Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
            

            如果您已经拥有像 MutableList 这样的 Eclipse Collections 类型,您可以执行以下操作:

            MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
            int[] ints = integers.asLazy().collectInt(i -> i).toArray();
            
            Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
            

            注意:我是 Eclipse Collections 的提交者

            【讨论】:

              【解决方案16】:

              使用 lambda 你可以做到这一点(在 jdk lambda 中编译):

              public static void main(String ars[]) {
                      TransformService transformService = (inputs) -> {
                          int[] ints = new int[inputs.size()];
                          int i = 0;
                          for (Integer element : inputs) {
                              ints[ i++ ] = element;
                          }
                          return ints;
                      };
              
                      List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };
              
                      int[] results = transformService.transform(inputs);
                  }
              
                  public interface TransformService {
                      int[] transform(List<Integer> inputs);
                  }
              

              【讨论】:

              • 当被问到这个问题时你不可能做到这一点,但这是现在处理这种情况的好方法(假设你已经升级了 Java)。您所做的工作可以进一步修改,以提供一种通用方法来使用相同的方法转换许多事物。 +1
              • 这里的解决方案只在循环代码中。其余部分(功能接口、lambda、main 方法、带有虚拟数据的列表)是无关紧要的,无助于回答问题。
              猜你喜欢
              • 2021-08-20
              • 2021-07-16
              • 2016-12-26
              • 1970-01-01
              相关资源
              最近更新 更多