如何在Java中将int[]转换为Integer[]?

213

我有一个长度为4的int[]数据集,我想计算每个特定组合的4个整数出现的次数。 这与在文档中计算单词频率非常相似。

我想创建一个Map<int[], double>,将每个int[]映射到在迭代列表时的运行计数,但是Map不接受原始类型。

所以我创建了Map<Integer[], Double>

我的数据存储为ArrayList<int[]>,因此我的循环应该类似于:

ArrayList<int[]> data = ... // load a dataset`

Map<Integer[], Double> frequencies = new HashMap<Integer[], Double>();

for(int[] q : data) {

    // **DO SOMETHING TO convert q from int[] to Integer[] so I can put it in the map

    if(frequencies.containsKey(q)) {
    frequencies.put(q, tfs.get(q) + p);
    } else {
        frequencies.put(q, p);
    }
}

我不确定在注释中需要什么代码才能使这个过程工作,以将int[]转换为Integer[]。或者也许我对正确的处理方式基本上感到困惑。


6
我想创建一个Map<int[], double>,但是Map不接受原始类型。正如下面的帖子之一指出的那样,int[]不是原始类型,所以这不是真正的问题。真正的问题是数组没有覆盖.equals()来比较元素。在这种意义上,转换为Integer[](如您的标题所示)并没有帮助您。在上面的代码中,frequencies.containsKey(q)仍然无法按预期工作,因为它使用.equals()进行比较。真正的解决方案是不在这里使用数组。 - newacct
不想再发另一个答案,但值得注意的是现在有一个文档示例关于这个问题。 - Mureinik
14个回答

262

Java 8本地化 (一行代码)

使用Java 8,int[]可以轻松转换为Integer[]

int[] data = {1,2,3,4,5,6,7,8,9,10};

// To boxed array
Integer[] what = Arrays.stream( data ).boxed().toArray( Integer[]::new );
Integer[] ever = IntStream.of( data ).boxed().toArray( Integer[]::new );

// To boxed list
List<Integer> you  = Arrays.stream( data ).boxed().collect( Collectors.toList() );
List<Integer> like = IntStream.of( data ).boxed().collect( Collectors.toList() );

正如他人所述,Integer[] 通常不是一个好的映射键。 但就转换而言,我们现在有了一个相对清晰和本地化的代码。


3
这是正确的方法。如果你需要将整数数组作为列表,可以这样写: List<Integer> list = IntStream.of(q).boxed().collect(Collectors.toList()); - aw-think
要将其转换为 Integer[],我建议使用以下语法:Integer[] boxed = IntStream.of(unboxed).boxed().toArray(); 与 @NwDx 类似的方式。 - YoYo
1
@JoD。是的,那样可以。但是IntStream.of无论如何都会调用Arrays.stream。我认为这归结于个人喜好-我更喜欢一个重载函数,有些人喜欢使用更明确的类。 - Sheepy
1
@VijayChavda 新语法称为方法引用,它是Java 8中lambda的一部分,于2014年推出(JSR 335 Part C)。它意味着Integer[]类的“新”方法(构造函数) - Sheepy
太复杂了!有一个非常简单的方法来做:int[] arrayOfInts = {1 , 3 , 5 , 6}; Integer[] arrayOfObjects = new Integer[arrayOfInts.length]; Arrays.setAll(arrayOfInts, i -> arrayOfObjects[i] = arrayOfInts[i] ); - undefined
显示剩余15条评论

83

如果你想将一个int[]转换成Integer[],在JDK中没有自动化的方法可以实现。不过你可以像下面这样处理:

int[] oldArray;

... // Here you would assign and fill oldArray

Integer[] newArray = new Integer[oldArray.length];
int i = 0;
for (int value : oldArray) {
    newArray[i++] = Integer.valueOf(value);
}

如果您可以访问Apache lang库,那么您可以像这样使用ArrayUtils.toObject(int[])方法:

Integer[] newArray = ArrayUtils.toObject(oldArray);

77
那是一种很恶劣的for循环方式。 - James Becwar
11
这对每个人来说都是完全正常的,我看不到什么不好的部分。 - Dahaka
18
@DahakaпјҢдёҚеҘҪзҡ„ең°ж–№еңЁдәҺеңЁжңүзҙўеј•еҸҳйҮҸiзҡ„жғ…еҶөдёӢдҪҝз”Ёvalueзҡ„иҝӯд»ЈеҷЁгҖӮ - lcn
1
@Icn,我能理解为什么有些人不喜欢那种风格,但是它为什么会如此令人讨厌呢? - Eddie
16
@icn,@Dahaka:不好的地方在于你们已经在使用递增索引变量了,所以没有必要再使用for-each循环;虽然在代码中它看起来漂亮简单,但在幕后却涉及到不必要的开销。在这里,传统的for (int i...)循环会更有效率。 - daiscog
显示剩余3条评论

21

将int[]转换为Integer[]:

    import java.util.Arrays;
    ...

    int[] aint = {1,2,3,4,5,6,7,8,9,10};
    Integer[] aInt = new Integer[aint.length];

    Arrays.setAll(aInt, i -> aint[i]);

11

仅使用普通for循环,无需外部库:

将int[]转换为Integer[]:

int[] primitiveArray = {1, 2, 3, 4, 5};
Integer[] objectArray = new Integer[primitiveArray.length];

for(int ctr = 0; ctr < primitiveArray.length; ctr++) {
    objectArray[ctr] = Integer.valueOf(primitiveArray[ctr]); // returns Integer value
}

将 Integer[] 转换为 int[]:

Integer[] objectArray = {1, 2, 3, 4, 5};
int[] primitiveArray = new int[objectArray.length];

for(int ctr = 0; ctr < objectArray.length; ctr++) {
    primitiveArray[ctr] = objectArray[ctr].intValue(); // returns int value
}

8
假设您希望地图的键匹配元素的值而不是数组的标识。这种情况下,您需要一种定义equalshashCode的对象,就像您期望的那样。最简单的方法是转换为List<Integer>,可以使用ArrayList或更好地使用Arrays.asList。比这更好的做法是引入一个表示数据的类(类似于java.awt.Rectangle),但我建议将变量设置为私有final,并且类也设置为final。

哦,这是一个数组转换问题,只不过是相反的方式:https://dev59.com/H3RB5IYBdhLWcg3wpYmo - Tom Hawtin - tackline

7

正确的解决方案是将这个类作为一个键来使用,用于包装实际的int[]。

public class IntArrayWrapper {
    int[] data;

    public IntArrayWrapper(int[] data) {
        this.data = data;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        IntArrayWrapper that = (IntArrayWrapper) o;

        if (!Arrays.equals(data, that.data))
            return false;

        return true;
    }

    @Override
    public int hashCode() {
        return data != null ? Arrays.hashCode(data) : 0;
    }
}

然后将您的代码更改为:

Map<IntArrayWrapper, Double > freqs = new HashMap<IntArrayWrapper, Double>();

for (int[] data : datas) {
    IntArrayWrapper wrapper = new IntArrayWrapper(data);

    if (freqs.containsKey(wrapper)) {
        freqs.put(wrapper, freqs.get(wrapper) + p);
    }

    freqs.put(wrapper, p);
}

1
我会将类设为final,字段设为private final。在构造函数中创建数组的防御性副本(克隆)。只需返回Arrays.equals的值,而不是使用那个奇怪的if语句。添加toString方法会更好。 - Tom Hawtin - tackline
1
哦,还要在构造函数中抛出NPE(可能调用克隆),以便于处理空数据,并且不需要在hashCode中进行检查。 - Tom Hawtin - tackline
真的..但是equals和hashCode的代码是由IDEA生成的:-)。它可以正常工作。 - Mihai Toader

7
  1. Convert int[] to Integer[]

     public static Integer[] toConvertInteger(int[] ids) {
    
         Integer[] newArray = new Integer[ids.length];
         for (int i = 0; i < ids.length; i++) {
             newArray[i] = Integer.valueOf(ids[i]);
         }
         return newArray;
     }
    
  2. Convert Integer[] to int[]

     public static int[] toint(Integer[] WrapperArray) {
    
        int[] newArray = new int[WrapperArray.length];
        for (int i = 0; i < WrapperArray.length; i++) {
            newArray[i] = WrapperArray[i].intValue();
        }
        return newArray;
     }
    

4
由于自动装箱,这个说法有些不准确。在第一个例子中,你可以简单地使用newArray[i] = ids[i];,在第二个例子中,你可以使用newArray[i] = WrapperArray[i]来实现:) - Eel Lee

5

不必编写自己的代码,您可以使用IntBuffer来包装现有的int[],而无需将数据复制到Integer数组中:

int[] a = {1, 2, 3, 4};
IntBuffer b = IntBuffer.wrap(a);

IntBuffer实现了comparable接口,因此您可以使用已经编写的代码。形式上,映射比较键,使得a.equals(b)用来表示两个键相等,因此,即使1,2,3数组位于不同的内存位置,具有这些数组的两个IntBuffers被认为是相等的,因此可以用于您的频率代码。

ArrayList<int[]> data = ... // Load a dataset`

Map<IntBuffer, Double> frequencies = new HashMap<IntBuffer, Double>();

for(int[] a : data) {

    IntBuffer q = IntBuffer.wrap(a);

    if(frequencies.containsKey(q)) {
        frequencies.put(q, tfs.get(q) + p);
    } else {
        frequencies.put(q, p);
    }
}

2
我不确定为什么你的地图需要一个Double。就你想要做的事情而言,你有一个int [],你只想知道每个序列出现的次数(?)。这为什么需要一个Double呢?
我会为int数组创建一个包装器,并使用适当的.equals和.hashCode方法来考虑int []对象本身在这些方法的版本中未考虑其数据的事实。
public class IntArrayWrapper {
    private int values[];

    public IntArrayWrapper(int[] values) {
        super();
        this.values = values;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(values);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IntArrayWrapper other = (IntArrayWrapper) obj;
        if (!Arrays.equals(values, other.values))
            return false;
        return true;
    }

}

然后使用Google Guava的多集合(multiset),该集合专门用于计算元素出现次数,只要您在其中放置的元素类型具有适当的.equals和.hashCode方法。

List<int[]> list = ...;
HashMultiset<IntArrayWrapper> multiset = HashMultiset.create();
for (int values[] : list) {
    multiset.add(new IntArrayWrapper(values));
}

然后,要获取任何特定组合的计数:
int cnt = multiset.count(new IntArrayWrapper(new int[] { 0, 1, 2, 3 }));

这个 IntArrayWrapper 绝对是使用 int[] 数组作为哈希键的正确方法,但应该提到这样的类型已经存在… 您可以使用它来包装一个数组,它不仅具有 hashCodeequals,甚至还是可比较的。 - Holger

2
这个非常好用!
int[] mInt = new int[10];
Integer[] mInteger = new Integer[mInt.length];

List<Integer> wrapper = new AbstractList<Integer>() {
    @Override
    public int size() {
        return mInt.length;
    }

    @Override
    public Integer get(int i) {
        return mInt[i];
    }
};

wrapper.toArray(mInteger);

嗨,Tunaki, 你能不能给我解释一下上面的代码?当我通过调试器运行时,我看到get和size方法自动被调用,即使它们没有被显式调用!为什么会这样?你能不能解释一下? - forkdbloke
就算这个方法运行良好,解释也是必要的。例如,这个方法的主意/核心是什么?它在哪个系统(包括版本)以及使用哪个版本的Java进行了测试?根据帮助中心的说法:“……一定要解释为什么你提出的解决方案是合适的,以及它是如何工作的。”请通过修改(更改)您的答案,而非在评论区回答(无需加上“编辑:”、“更新:”或类似的字眼——答案应该看起来像是今天写的)。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接