我是Java的新手,非常困惑。
我有一个长度为4 int[]的大型数据集,我想计算次数
每个4个整数的特定组合都会出现。 这与计算文档中的单词频率非常相似。
我想创建一个Map,将列表迭代时将每个int []映射到一个运行计数,但是Map不采用原始类型。
所以我做了Map
我的数据存储为ArrayList,所以我的循环应类似于
ArrayList data = ... // load a dataset`
Map frequencies = new HashMap();
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[]。 也许我从根本上对正确的方法感到困惑。
"我想创建一个Map ...但是Map不会采用原始类型。" 正如下面指出的帖子之一,int []不是原始类型,因此这不是真正的问题。 真正的问题是数组不会重写.equals()来比较元素。 从这种意义上讲,转换为Integer [](如您的标题所述)对您没有帮助。 在上面的代码中,frequency.containsKey(q)仍然无法按预期工作,因为它使用.equals()进行比较。 真正的解决方案是不在这里使用数组。
不想用另一个答案来发送垃圾邮件,但现在值得注意的是有关此问题的文档示例。
本机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 you = Arrays.stream( data ).boxed().collect( Collectors.toList() );
List like = IntStream.of( data ).boxed().collect( Collectors.toList() );
正如其他人所说,Integer[]通常不是一个好的地图密钥。
但就转换而言,我们现在拥有一个相对干净的本机代码。
这就是正确的方法。如果需要将Integer-Array作为列表??,可以编写:Listlist = IntStream.of(q).boxed().collect(Collectors.toList());
转换为Integer[]我实际建议使用以下语法:Integer[] boxed = IntStream.of(unboxed).boxed().toArray();以与@NwDx类似的方式
@JoD。是的,这很有效。但是IntStream.of仍然会调用Arrays.stream。我认为这取决于个人喜好-我更喜欢一个重写的功能,有些喜欢使用更明确的类。
在您的示例中修复toArray的签名,然后我们同意。事实上,我可能更喜欢你的版本。
@JoD。是的,这很难过。但只要流被装箱(即不是IntStream),toArray总是需要一个构造函数,无论源是什么。
不...那是我想说的...它不需要一个...
@JoD。我收到编译错误Object[] cannot be converted to Integer[]。在我的PC和ideone上:ideone.com/uagsSd
@Sheepy:我更喜欢IntStream的用法,因为它与该流中的数据类型更相关。 Arrays类更多地用于操作数组而不是流(即使某些方法创建了流)。因此,如果第三方正在阅读您的代码,则他/她完全知道发生了什么。更具可读性的是:对该int数组进行IntStream处理,将其装箱,然后创建一个数组或收集列表。就像您说的那样:数组从该int数组(什么类型的?)生成流并将其装箱(到什么?)。但这一切都取决于品味。
我在吃我的鞋子。我错了 - 我以为我试过了,但显然没有。 boxed()仅返回类型为Stream的内容,但是toArray仍需要类型化数组生成器以返回正确类型的Array,否则它将为Object[]。我想这也有好处,而且可能没有别的办法。
感谢您对JoD的支持。我从一个数组的参数类型开始,当您使用一个函数处理大多数数组时,它是统一的。但是我只是想我可以在答案中添加两种语法:p @NwDx
@NwDx不知何故我也本能地使用IntStream.of,但我认为Arrays.stream会受到许多人的青睐,因为它的类型中立是由于超载。
@JoD。完全确认。如果一个人不知道他/她不能创建一个整数数组的数据类型,因为你需要创建数据的类型。只有带收集器的无类型列表才有可能。还是我错了?
我们需要考虑在JEP 169中可能不推荐使用显式原始类型的类。
@JoD。我看不到JEP 169在哪里提到了对框式原始类的弃用。此外,它的优先级较低,并且进度不存在。
@NwDx好吧,与Arrays.stream,IntStream.of和其他原始流相比,还需要您了解数据类型。实际上,如果数据类型发生更改,则后者只会导致更多代码更改。
@Sheepy项目Valhalla的一部分。弃用只是我对未来事物的插补。
那是一个疯狂但伟大的解决方案!谢谢!
这可以应用于2D阵列吗?可以int[][] data转换为Integer[][] whatever吗?
@Chetan可以应用于多个维度,但我强烈反对它(更好地使用正确的循环),因为这种方法根本无法扩展:Integer[][] newData = Arrays.stream( data ).map( row -> Arrays.stream( row ).boxed().toArray( Integer[]::new ) ).toArray( Integer[][]::new ) -
这个新语法是什么:Integer[]::new?
@VijayChavda 2014年,Java 8作为lambda的一部分(JSR 335 Part C)引入了称为方法引用的新语法。这表示the"new" method (constructor) of the Integer[] class。
如果要将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);
+1使用ArrayUtils。
多数民众赞成在一个讨厌的方式做一个循环。
这对每个人来说都是完全正常的......我没有看到令人讨厌的部分。
@Dahaka,糟糕的是使用value的迭代器,而索引变量i就在那里。
@Icn,我明白为什么有些人不喜欢这种风格,但是是什么让它如此讨厌以至于变得讨厌呢?
使用番石榴,我更喜欢ListintList = Ints.asList(oldArray);
@icn,@ Dahaka:糟糕的是,因为你已经在使用递增索引变量,所以也不需要使用for-each;尽管它在代码中看起来很漂亮而且很简单,但是在幕后隐藏了不必要的开销。传统的for (int i...)循环在这里会更有效。
使用不带外部库的常规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
}
超级machan !!谢谢@ohtph
据推测,您希望映射的键匹配元素的值而不是数组的标识。在那种情况下,您需要某种可以定义equals和hashCode的对象。最简单的是转换为List,ArrayList或更好地使用Arrays.asList。更好的是,您可以引入一个代表数据的类(类似于java.awt.Rectangle,但我建议将变量设置为private final,并将类也设置为final)。
哦,这是一个数组转换问题,反之亦然:stackoverflow.com/questions/564392/
将int []转换为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;
}
将Integer []转换为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;
}
由于自动装箱,这是相当不准确的。在第一个示例中,您可以简单地执行newArray[i] = ids[i];,而在第二个示例中,只需执行newArray[i] = WrapperArray[i] :)
我在先前的回答中错了。正确的解决方案是使用此类作为包装实际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 freqs = new HashMap();
for (int[] data : datas) {
IntArrayWrapper wrapper = new IntArrayWrapper(data);
if ( freqs.containsKey(wrapper)) {
freqs.put(wrapper, freqs.get(wrapper) + p);
}
freqs.put(wrapper, p);
}
将课程设为班级决赛,然后将田径赛场设为私人决赛。在构造函数(clone)中创建数组的防御副本。只需从Arrays.equals返回值,而不要使用特殊的if语句。 toString会很好。
哦,从构造函数中抛出一个NPE(可能调用clone)以获取空数据,并且不要将其签入hashCode。
是的..但是等号的代码,hashCode是由IDEA :-)生成的。它工作正常。
您可以使用IntBuffer来包装现有的int [],而不必将数据复制到Integer数组中,而不是编写自己的代码。
int[] a = {1,2,3,4};
IntBuffer b = IntBuffer.wrap(a);
IntBuffer实现了可比性,因此您可以使用已编写的代码。正式地映射比较键,以便使用a.equals(b)表示两个键相等,因此,即使数组位于不同的内存位置,两个具有数组1,2,3的IntBuffer也被称为相等,因此适合您的频率代码。
ArrayList data = ... // load a dataset`
Map frequencies = new HashMap();
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);
}
}
希望有所帮助
这就像一个魅力!
int[] mInt = new int[10];
Integer[] mInteger = new Integer[mInt.length];
List wrapper = new AbstractList() {
@Override
public int size() {
return mInt.length;
}
@Override
public Integer get(int i) {
return mInt[i];
}
};
wrapper.toArray(mInteger);
不确定为什么你需要在你的地图中使用Double。就你要做的事情来说,你有一个int []而你只想要计算每个序列出现的次数?为什么这需要Double呢?
我要做的是使用适当的.equals和.hashCode方法为int数组创建包装器,以解决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 list = ...;
HashMultiset 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[]数组作为哈希键的正确方法,但是应该指出的是,这样的类型已经存在……您可以使用它来包装数组,而不仅仅是hashCode和< x10>,它甚至可比。
更新:虽然下面编译,但它会在运行时抛出ArrayStoreException。太糟糕了。我让它留作以后参考。
将int[]转换为Integer[]:
int[] old;
...
Integer[] arr = new Integer[old.length];
System.arraycopy(old, 0, arr, 0, old.length);
我必须承认,考虑到System.arraycopy是低级的,一切都会编译,我对此感到有些惊讶,但是它确实可以。至少在java7中。
您可以轻松地转换其他方式。
当此答案不起作用时,我认为保留此答案"以供参考"没有太大价值。 System.arraycopy()的文档甚至指出,它不能用于此目的。
你不需要。 int[]是一个对象,可以用作地图内的键。
Map frequencies = new HashMap();
是频率图的正确定义。
这是错的:-)。也发布了正确的解决方案:-)。
?
非常感谢您的回复我先尝试了这个并且编译得很好,但似乎frequencies.containsKey(q)总是假的,即使Ive put两次相同的数组 - 这里有一些故障涉及javas定义与int []相等S'
Map ,Integer>可以更好地工作。
(提示,(new int [0])。equals(new int [0])为false;(new ArrayList ())。equals(new ArrayList ())为true。
不好的主意,因为数组比较是基于引用相等性的。那就是为什么Arrays.equals()存在的原因...
该死的 :-)。我希望我是对的。声明是正确的,但是由于引用相等性的原因,语义是错误的。
只需使用:
public static int[] intArrayToIntegerArray(Integer[] array)
{
int[] g = new int[array.length];
for(int i = 0; i < array.length; i++){
g[i] = array[i];
}
return g;
}