Related
I have tried the following codes, but I'm still getting errors. It seems I have a problem in comparing two arrays, and checking if they point at one array. I also have a problem in swapping two arrays so that they can interchange their values. Additionally, removing values that are the same in an array seems to be so hard. The codes below is how I pictured them, but I'm still getting errors even after trying different approaches to the problems. Please help me understand how to compare two arrays, specifically on these codes.
public class ArraySwap {
public static void main(String[] args) {
//Some test code
ArraySwap swapper = new ArraySwap();
int[] a = {1, 2, 3}; //initialize array a[]
int[] b = a; //initialize array b[]
System.out.println(swapper.arrayEquals(a, b));
int[] arr = {1, 1, 2, 3, 4, 1, 5, 6, 8, 7, 9, 9, 8, 9, 1};
ArraySwap c = new ArraySwap();
arr = c.removeDuplicates(arr);
for (Integer i : arr) {
System.out.print(i);
}
System.out.println();
}
/*
Return true if the values in a are the same as the values in b
*/
public boolean arrayValuesEqual(int[] a, int[] b) {
if (Arrays.equals(a, b)) {
return true; //returning true
} else {
return false;
}
}
/*
Return true if a and b point to the same array
*/
public boolean arrayEquals(int[] a, int[] b) {
if (a.length == b.length) {
return true;
} else {
return false;
}
}
/*
* Swap a and b WITHOUT doing an elementwise copy.
*/
public void swap(int[] a, int[] b) {
int temp = a[0];
a[0] = b[0];
b[0] = temp;
}
}
/*
* Returns true if a and b have the same name
*/
public boolean sameName(Person a, Person b) {
if (a == b) {
return true;
} else {
return false;
}
}
/*
* Given an array of positive integers, removes duplicates
* in the array.
* #return a contiguous array with the remaining integers
* with a length equal to the number of remaining integers
*/
public int[] removeDuplicates(int[] integers) {
int[] toReturn = new int[];
for (int i = 0; i > integers.length; i++) {
if (i + 1 > integers.length) {
if (integers[i] == integers[i + 1]) {
remove.integers[i];
}
}
toReturn = integers[i];
}
return toReturn;
}
}
You seemed to have asked a few questions in one and it's not really clear what your goal is....
In your arrayValuesEqual() you're comparing arrays a & b with .equals this method is comparing a shallow copy of the arrays. If you want to do a deep copy you should use .deepEquals(). see more info here: comparing arrays in java
in your arrayEquals method the description reads if they point to the same array, but all you're doing is checking the length.. this does not prove that the contains are the same...
your swap method - will this work if it's a multidimensional array? What if they are not the same length array? You seem to be writing code for a specific case and not considering various test cases.
Your sameName method - that's not how you compare objects. the == compares object references, it checks to see if the two operands point to the same object (not equivalent objects, the same object). You will need to override an equals method for the Person object.
Suppose we have the Java code:
Object arr = Array.newInstance(Array.class, 5);
Would that run? As a further note, what if we were to try something like this:
Object arr1 = Array.newInstance(Array.class, 2);
Object arr2 = Array.newInstance(String.class, 4);
Object arr3 = Array.newInstance(String.class, 4);
Array.set(arr1, 0, arr2);
Array.set(arr1, 1, arr3);
Would arr1 then be a 2D array equivalent to:
String[2][4] arr1;
How about this: what if we don't know the dimensions of this array until runtime?
Edit: if this helps (I'm sure it would...) we're trying to parse an array of unknown dimensions from a String of the form
[value1, value2, ...]
or
[ [value11, value12, ...] [value21, value22, ...] ...]
And so on
Edit2: In case someone as stupid as I am tries this junk, here's a version that at least compiles and runs. Whether or not the logic is sound is another question entirely...
Object arr1 = Array.newInstance(Object.class, x);
Object arr11 = Array.newInstance(Object.class, y);
Object arr12 = Array.newInstance(Object.class, y);
...
Object arr1x = Array.newInstance(Object.class, y);
Array.set(arr1, 0, arr11);
Array.set(arr1, 1, arr12);
...
Array.set(arr1, x-1, arr1x);
And so on. It just has to be a giant nested array of Objects
It is actually possible to do in java. (I'm a bit surprised I must say.)
Disclaimer; I never ever want to see this code anywhere else than as an answer to this question. I strongly encourage you to use Lists.
import java.lang.reflect.Array;
import java.util.*;
public class Test {
public static int[] tail(int[] arr) {
return Arrays.copyOfRange(arr, 1, arr.length);
}
public static void setValue(Object array, String value, int... indecies) {
if (indecies.length == 1)
((String[]) array)[indecies[0]] = value;
else
setValue(Array.get(array, indecies[0]), value, tail(indecies));
}
public static void fillWithSomeValues(Object array, String v, int... sizes) {
for (int i = 0; i < sizes[0]; i++)
if (sizes.length == 1)
((String[]) array)[i] = v + i;
else
fillWithSomeValues(Array.get(array, i), v + i, tail(sizes));
}
public static void main(String[] args) {
// Randomly choose number of dimensions (1, 2 or 3) at runtime.
Random r = new Random();
int dims = 1 + r.nextInt(3);
// Randomly choose array lengths (1, 2 or 3) at runtime.
int[] sizes = new int[dims];
for (int i = 0; i < sizes.length; i++)
sizes[i] = 1 + r.nextInt(3);
// Create array
System.out.println("Creating array with dimensions / sizes: " +
Arrays.toString(sizes).replaceAll(", ", "]["));
Object multiDimArray = Array.newInstance(String.class, sizes);
// Fill with some
fillWithSomeValues(multiDimArray, "pos ", sizes);
System.out.println(Arrays.deepToString((Object[]) multiDimArray));
}
}
Example Output:
Creating array with dimensions / sizes: [2][3][2]
[[[pos 000, pos 001], [pos 010, pos 011], [pos 020, pos 021]],
[[pos 100, pos 101], [pos 110, pos 111], [pos 120, pos 121]]]
Arrays are type-safe in java - that applies to simple arrays and "multi-dimensional" arrays - i.e. arrays of arrays.
If the depth of nesting is variable at runtime, then the best you can do is to use an array that corresponds to the known minimum nesting depth (presumably 1.) The elements in this array with then either be simple elements, or if further nesting is required, another array. An Object[] array will allow you to do this, since nested arrays themselves are also considered Objects, and so fit within the type system.
If the nesting is completely regular, then you can preempt this regularity and create an appropriate multimensional array, using Array.newInstance(String.class, dimension1, dimension2, ...), If nesting is irregular, you will be better off using nested lists, which allow for a "jagged" structure and dynamic sizing. You can have a jagged structure, at the expence of generics. Generics cannot be used if the structure is jagged since some elements may be simple items while other elements may be further nested lists.
So you can pass multiple dimensions to Array.newInstance, but that forces a fixed length for each dimension. If that's OK, you can use this:
// We already know from scanning the input that we need a 2 x 4 array.
// Obviously this array would be created some other way. Probably through
// a List.toArray operation.
final int[] dimensions = new int[2];
dimensions[0] = 2;
dimensions[1] = 4;
// Create the array, giving the dimensions as the second input.
Object array = Array.newInstance(String.class, dimensions);
// At this point, array is a String[2][4].
// It looks like this, when the first dimension is output:
// [[Ljava.lang.String;#3e25a5, [Ljava.lang.String;#19821f]
//
// The second dimensions look like this:
// [null, null, null, null]
The other option would be to build them up from the bottom, using getClass on the previous level of array as the input for the next level. The following code runs and produces a jagged array as defined by the nodes:
import java.lang.reflect.Array;
public class DynamicArrayTest
{
private static class Node
{
public java.util.List<Node> children = new java.util.LinkedList<Node>();
public int length = 0;
}
public static void main(String[] args)
{
Node node1 = new Node();
node1.length = 1;
Node node2 = new Node();
node2.length = 2;
Node node3 = new Node();
node3.length = 3;
Node node4 = new Node();
node4.children.add(node1);
node4.children.add(node2);
Node node5 = new Node();
node5.children.add(node3);
Node node6 = new Node();
node6.children.add(node4);
node6.children.add(node5);
Object array = createArray(String.class, node6);
outputArray(array); System.out.println();
}
private static Object createArray(Class<?> type, Node root)
{
if (root.length != 0)
{
return Array.newInstance(type, root.length);
}
else
{
java.util.List<Object> children = new java.util.ArrayList<Object>(root.children.size());
for(Node child : root.children)
{
children.add(createArray(type, child));
}
Object array = Array.newInstance(children.get(0).getClass(), children.size());
for(int i = 0; i < Array.getLength(array); ++i)
{
Array.set(array, i, children.get(i));
}
return array;
}
}
private static void outputArray(Object array)
{
System.out.print("[ ");
for(int i = 0; i < Array.getLength(array); ++i)
{
Object element = Array.get(array, i);
if (element != null && element.getClass().isArray())
outputArray(element);
else
System.out.print(element);
System.out.print(", ");
}
System.out.print("]");
}
}
As a further note, what if we were to try something like this:
Object arr1 = Array.newInstance(Array.class, 2);
Object arr2 = Array.newInstance(String.class, 4);
Object arr3 = Array.newInstance(String.class, 4);
Array.set(arr1, 0, arr2);
...
No, you can't set an String[] value like that. You run into
Exception in thread "main" java.lang.IllegalArgumentException: array element type mismatch
at java.lang.reflect.Array.set(Native Method)
at Test.main(Test.java:12)
Ok, if you are unsure of the dimensions of the array, then the following method won't work. However, if you do know the dimensions, do not use reflection. Do the following:
You can dynamically build 2d arrays much easier than that.
int x = //some value
int y = //some other value
String[][] arr = new String[x][y];
This will 'dynamically' create an x by y 2d array.
So I came across this question with code to extract coefficients from a polynomial with variable numbers of variables. So a user might
want the coefficient array for a polynomial in two variables 3 x^2 + 2 x y or it could be one with three variables. Ideally, you want a multiple dimension array which the user can easily interrogate so can be cast to
Integer[], Integer[][] etc.
This basically uses the same technique as jdmichal's answer, using the Array.newInstance(obj.getClass(), size) method. For a multi dimensional arrays obj can be an array of one less dimension.
Sample code with randomly created elements
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
public class MultiDimArray {
static Random rand = new Random();
/**
* Create an multi-dimensional array
* #param depth number of dimensions
* #return
*/
static Object buildArray(int depth) {
if(depth ==1) { // For 1D case just use a normal array
int size = rand.nextInt(3)+1;
Integer[] res = new Integer[size];
for(int i=0;i<size;++i) {
res[i] = new Integer(i);
}
return res;
}
// 2 or more dimensions, using recursion
int size = rand.nextInt(3)+1;
// Need to get first items so can find its class
Object ele0 = buildArray(depth-1);
// create array of correct type
Object res = Array.newInstance(ele0.getClass(), size);
Array.set(res, 0, ele0);
for(int i=1;i<size;++i) {
Array.set(res, i, buildArray(depth-1));
}
return res;
}
public static void main(String[] args) {
Integer[] oneD = (Integer[]) buildArray(1);
System.out.println(Arrays.deepToString(oneD));
Integer[][] twoD = (Integer[][]) buildArray(2);
System.out.println(Arrays.deepToString(twoD));
Integer[][][] threeD = (Integer[][][]) buildArray(3);
System.out.println(Arrays.deepToString(threeD));
}
}
Effective Java item # (I don't remember ) : Know and use the libraries.
You can use a List and use the toArray method:
List<String[]> twoDimension = new ArrayList<String[]>();
To convert it to an array you would use:
String [][] theArray = twoDimension.toArray( new String[twoDimension.size()][] );
The trick is, the outer array is declared to hold String[] ( string arrays ) which in turn can be dynamically created with another List<String> or, if your're parsing strings with the String.split method.
Demo
Focusing on the dynamic creation of the array and not in the parsing, here's an example on how does it works used in conjunction with String.split
// and array which contains N elements of M size
String input = "[[1],[2,3],[4,5,6,7],[8,9,10,11,12,13]]";
// Declare your dynamic array
List<String[]> multiDimArray = new ArrayList<String[]>();
// split where ],[ is found, just ignore the leading [[ and the trailing ]]
String [] parts = input.replaceAll("\\[\\[|\\]\\]","")
.split("\\],\\[");
// now split by comma and add it to the list
for( String s : parts ){
multiDimArray.add( s.split(",") ) ;
}
String [][] result = multiDimArray.toArray( new String[multiDimArray.size()][]);
There. Now your result is a two dimensional dynamically created array containing : [[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]] as expected.
Here's a complete running demo, which also adds more regexp to the mix, to eliminate white spaces.
I let you handle the other scenarios.
I am attempting to sort an array of integers such that all even numbers precede odd numbers, without using any external libraries.
You may recognize this from: http://codingbat.com/prob/p105771
" Return an array that contains the exact same numbers as the given array, but rearranged so that all the even numbers come before all the odd numbers. Other than that, the numbers can be in any order. You may modify and return the given array, or make a new array. "
I have code that accomplishes this goal:
public int[] evenOdd(int[] nums) {
int c=0;
int c2=0;
int [] nums2=new int[nums.length];
for(int i=0;i<nums.length;i++)
{
if(nums[i]%2==0)
{
nums2[c]=nums[i];
c++;
}
else
{
nums2[nums.length-c2-1]=nums[i];
c2++;
}
}
return nums2;
}
I have also approached the problem by calling array.sort() and then inserting the numbers by index, incrementing by two, then inserting the remainder. This also works.
So, to make a long post short-is there a more elegant way to accomplish this goal in future?
Thanks!
Just a follow-up to my comment. Here is how you can do it in O(n) without extra-space:
public class Main {
public static void main(String[] args) {
evenOdd(new int[]{1, 2, 3, 4, 5, 6, 7});
evenOdd(new int[]{2, 3, 4, 5, 6, 7});
evenOdd(new int[]{1, 1, 1, 1, 1});
evenOdd(new int[]{2, 2, 2, 2});
}
public static void evenOdd(int[] a) {
int firstOdd = 0;
for (int i = 0; i < a.length; ++i) {
if (a[i] % 2 == 0) {
int t = a[firstOdd];
a[firstOdd] = a[i];
a[i] = t;
firstOdd++;
// } else {
// else is redundant, just leave odd in-place
}
}
System.out.println(Arrays.toString(a));
}
}
Create a wrapper object that contains an int, call it SortingWrapper. This object should implement Comparable, such that its natural sort order is based on the sort order of value%2. Then just sort the array with Arrays.sort(). Based on the compareTo() implementation, the evens will naturally (ie, according to their natural sort order) bubble one way, all the odds will bubble the other.
Alternatively, you could just uses Integers as your wrapper and pass a Comparator that does the same thing to Arrays.sort().
edit- here is the general idea. You might have to play around with the sort order, but I think this pretty much works. I suspect that this array will count as "mostly sorted" which would make performance tend more towards O(n) than log(n), based upon the javadoc for Arrays.sort().
public void sortOddsAndEvents(Integer[] input)
{
Arrays.sort(input, new Comparator<Integer>()
{
#Override
public int compare(Integer arg0, Integer arg1)
{
if (arg0.equals(arg1)) return 0;
else return Integer.compare(arg0.intValue()%2, arg1.intValue()%2);
}
});
}
public int[] evenOdd(int[] nums) {
int evenCounter = -1, oddCounter = nums.length;
int[] ordered = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
int current = (nums[i] % 2 == 0) ? ++evenCounter : --oddCounter;
ordered[current] = nums[i];
}
return ordered;
}
Suppose we have the Java code:
Object arr = Array.newInstance(Array.class, 5);
Would that run? As a further note, what if we were to try something like this:
Object arr1 = Array.newInstance(Array.class, 2);
Object arr2 = Array.newInstance(String.class, 4);
Object arr3 = Array.newInstance(String.class, 4);
Array.set(arr1, 0, arr2);
Array.set(arr1, 1, arr3);
Would arr1 then be a 2D array equivalent to:
String[2][4] arr1;
How about this: what if we don't know the dimensions of this array until runtime?
Edit: if this helps (I'm sure it would...) we're trying to parse an array of unknown dimensions from a String of the form
[value1, value2, ...]
or
[ [value11, value12, ...] [value21, value22, ...] ...]
And so on
Edit2: In case someone as stupid as I am tries this junk, here's a version that at least compiles and runs. Whether or not the logic is sound is another question entirely...
Object arr1 = Array.newInstance(Object.class, x);
Object arr11 = Array.newInstance(Object.class, y);
Object arr12 = Array.newInstance(Object.class, y);
...
Object arr1x = Array.newInstance(Object.class, y);
Array.set(arr1, 0, arr11);
Array.set(arr1, 1, arr12);
...
Array.set(arr1, x-1, arr1x);
And so on. It just has to be a giant nested array of Objects
It is actually possible to do in java. (I'm a bit surprised I must say.)
Disclaimer; I never ever want to see this code anywhere else than as an answer to this question. I strongly encourage you to use Lists.
import java.lang.reflect.Array;
import java.util.*;
public class Test {
public static int[] tail(int[] arr) {
return Arrays.copyOfRange(arr, 1, arr.length);
}
public static void setValue(Object array, String value, int... indecies) {
if (indecies.length == 1)
((String[]) array)[indecies[0]] = value;
else
setValue(Array.get(array, indecies[0]), value, tail(indecies));
}
public static void fillWithSomeValues(Object array, String v, int... sizes) {
for (int i = 0; i < sizes[0]; i++)
if (sizes.length == 1)
((String[]) array)[i] = v + i;
else
fillWithSomeValues(Array.get(array, i), v + i, tail(sizes));
}
public static void main(String[] args) {
// Randomly choose number of dimensions (1, 2 or 3) at runtime.
Random r = new Random();
int dims = 1 + r.nextInt(3);
// Randomly choose array lengths (1, 2 or 3) at runtime.
int[] sizes = new int[dims];
for (int i = 0; i < sizes.length; i++)
sizes[i] = 1 + r.nextInt(3);
// Create array
System.out.println("Creating array with dimensions / sizes: " +
Arrays.toString(sizes).replaceAll(", ", "]["));
Object multiDimArray = Array.newInstance(String.class, sizes);
// Fill with some
fillWithSomeValues(multiDimArray, "pos ", sizes);
System.out.println(Arrays.deepToString((Object[]) multiDimArray));
}
}
Example Output:
Creating array with dimensions / sizes: [2][3][2]
[[[pos 000, pos 001], [pos 010, pos 011], [pos 020, pos 021]],
[[pos 100, pos 101], [pos 110, pos 111], [pos 120, pos 121]]]
Arrays are type-safe in java - that applies to simple arrays and "multi-dimensional" arrays - i.e. arrays of arrays.
If the depth of nesting is variable at runtime, then the best you can do is to use an array that corresponds to the known minimum nesting depth (presumably 1.) The elements in this array with then either be simple elements, or if further nesting is required, another array. An Object[] array will allow you to do this, since nested arrays themselves are also considered Objects, and so fit within the type system.
If the nesting is completely regular, then you can preempt this regularity and create an appropriate multimensional array, using Array.newInstance(String.class, dimension1, dimension2, ...), If nesting is irregular, you will be better off using nested lists, which allow for a "jagged" structure and dynamic sizing. You can have a jagged structure, at the expence of generics. Generics cannot be used if the structure is jagged since some elements may be simple items while other elements may be further nested lists.
So you can pass multiple dimensions to Array.newInstance, but that forces a fixed length for each dimension. If that's OK, you can use this:
// We already know from scanning the input that we need a 2 x 4 array.
// Obviously this array would be created some other way. Probably through
// a List.toArray operation.
final int[] dimensions = new int[2];
dimensions[0] = 2;
dimensions[1] = 4;
// Create the array, giving the dimensions as the second input.
Object array = Array.newInstance(String.class, dimensions);
// At this point, array is a String[2][4].
// It looks like this, when the first dimension is output:
// [[Ljava.lang.String;#3e25a5, [Ljava.lang.String;#19821f]
//
// The second dimensions look like this:
// [null, null, null, null]
The other option would be to build them up from the bottom, using getClass on the previous level of array as the input for the next level. The following code runs and produces a jagged array as defined by the nodes:
import java.lang.reflect.Array;
public class DynamicArrayTest
{
private static class Node
{
public java.util.List<Node> children = new java.util.LinkedList<Node>();
public int length = 0;
}
public static void main(String[] args)
{
Node node1 = new Node();
node1.length = 1;
Node node2 = new Node();
node2.length = 2;
Node node3 = new Node();
node3.length = 3;
Node node4 = new Node();
node4.children.add(node1);
node4.children.add(node2);
Node node5 = new Node();
node5.children.add(node3);
Node node6 = new Node();
node6.children.add(node4);
node6.children.add(node5);
Object array = createArray(String.class, node6);
outputArray(array); System.out.println();
}
private static Object createArray(Class<?> type, Node root)
{
if (root.length != 0)
{
return Array.newInstance(type, root.length);
}
else
{
java.util.List<Object> children = new java.util.ArrayList<Object>(root.children.size());
for(Node child : root.children)
{
children.add(createArray(type, child));
}
Object array = Array.newInstance(children.get(0).getClass(), children.size());
for(int i = 0; i < Array.getLength(array); ++i)
{
Array.set(array, i, children.get(i));
}
return array;
}
}
private static void outputArray(Object array)
{
System.out.print("[ ");
for(int i = 0; i < Array.getLength(array); ++i)
{
Object element = Array.get(array, i);
if (element != null && element.getClass().isArray())
outputArray(element);
else
System.out.print(element);
System.out.print(", ");
}
System.out.print("]");
}
}
As a further note, what if we were to try something like this:
Object arr1 = Array.newInstance(Array.class, 2);
Object arr2 = Array.newInstance(String.class, 4);
Object arr3 = Array.newInstance(String.class, 4);
Array.set(arr1, 0, arr2);
...
No, you can't set an String[] value like that. You run into
Exception in thread "main" java.lang.IllegalArgumentException: array element type mismatch
at java.lang.reflect.Array.set(Native Method)
at Test.main(Test.java:12)
Ok, if you are unsure of the dimensions of the array, then the following method won't work. However, if you do know the dimensions, do not use reflection. Do the following:
You can dynamically build 2d arrays much easier than that.
int x = //some value
int y = //some other value
String[][] arr = new String[x][y];
This will 'dynamically' create an x by y 2d array.
So I came across this question with code to extract coefficients from a polynomial with variable numbers of variables. So a user might
want the coefficient array for a polynomial in two variables 3 x^2 + 2 x y or it could be one with three variables. Ideally, you want a multiple dimension array which the user can easily interrogate so can be cast to
Integer[], Integer[][] etc.
This basically uses the same technique as jdmichal's answer, using the Array.newInstance(obj.getClass(), size) method. For a multi dimensional arrays obj can be an array of one less dimension.
Sample code with randomly created elements
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
public class MultiDimArray {
static Random rand = new Random();
/**
* Create an multi-dimensional array
* #param depth number of dimensions
* #return
*/
static Object buildArray(int depth) {
if(depth ==1) { // For 1D case just use a normal array
int size = rand.nextInt(3)+1;
Integer[] res = new Integer[size];
for(int i=0;i<size;++i) {
res[i] = new Integer(i);
}
return res;
}
// 2 or more dimensions, using recursion
int size = rand.nextInt(3)+1;
// Need to get first items so can find its class
Object ele0 = buildArray(depth-1);
// create array of correct type
Object res = Array.newInstance(ele0.getClass(), size);
Array.set(res, 0, ele0);
for(int i=1;i<size;++i) {
Array.set(res, i, buildArray(depth-1));
}
return res;
}
public static void main(String[] args) {
Integer[] oneD = (Integer[]) buildArray(1);
System.out.println(Arrays.deepToString(oneD));
Integer[][] twoD = (Integer[][]) buildArray(2);
System.out.println(Arrays.deepToString(twoD));
Integer[][][] threeD = (Integer[][][]) buildArray(3);
System.out.println(Arrays.deepToString(threeD));
}
}
Effective Java item # (I don't remember ) : Know and use the libraries.
You can use a List and use the toArray method:
List<String[]> twoDimension = new ArrayList<String[]>();
To convert it to an array you would use:
String [][] theArray = twoDimension.toArray( new String[twoDimension.size()][] );
The trick is, the outer array is declared to hold String[] ( string arrays ) which in turn can be dynamically created with another List<String> or, if your're parsing strings with the String.split method.
Demo
Focusing on the dynamic creation of the array and not in the parsing, here's an example on how does it works used in conjunction with String.split
// and array which contains N elements of M size
String input = "[[1],[2,3],[4,5,6,7],[8,9,10,11,12,13]]";
// Declare your dynamic array
List<String[]> multiDimArray = new ArrayList<String[]>();
// split where ],[ is found, just ignore the leading [[ and the trailing ]]
String [] parts = input.replaceAll("\\[\\[|\\]\\]","")
.split("\\],\\[");
// now split by comma and add it to the list
for( String s : parts ){
multiDimArray.add( s.split(",") ) ;
}
String [][] result = multiDimArray.toArray( new String[multiDimArray.size()][]);
There. Now your result is a two dimensional dynamically created array containing : [[1], [2, 3], [4, 5, 6, 7], [8, 9, 10, 11, 12, 13]] as expected.
Here's a complete running demo, which also adds more regexp to the mix, to eliminate white spaces.
I let you handle the other scenarios.
I have a large dataset of length 4 int[] and I want to count the number of times that each particular combination of 4 integers occurs. This is very similar to counting word frequencies in a document.
I want to create a Map<int[], double> that maps each int[] to a running count as the list is iterated over, but Map doesn't take primitive types.
So I made Map<Integer[], Double>.
My data is stored as an ArrayList<int[]>, so my loop should be something like:
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);
}
}
I'm not sure what code I need at the comment to make this work to convert an int[] to an Integer[]. Or maybe I'm fundamentally confused about the right way to do this.
Native Java 8 (one line)
With Java 8, int[] can be converted to Integer[] easily:
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() );
As others stated, Integer[] is usually not a good map key.
But as far as conversion goes, we now have a relatively clean and native code.
If you want to convert an int[] to an Integer[], there isn't an automated way to do it in the JDK. However, you can do something like this:
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);
}
If you have access to the Apache lang library, then you can use the ArrayUtils.toObject(int[]) method like this:
Integer[] newArray = ArrayUtils.toObject(oldArray);
Convert int[] to 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]);
Using regular for-loop without external libraries:
Convert int[] to 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
}
Convert Integer[] to 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
}
Presumably you want the key to the map to match on the value of the elements instead of the identity of the array. In that case you want some kind of object that defines equals and hashCode as you would expect. Easiest is to convert to a List<Integer>, either an ArrayList or better use Arrays.asList. Better than that you can introduce a class that represents the data (similar to java.awt.Rectangle but I recommend making the variables private final, and the class final too).
The proper solution is to use this class as a key in the map wrapping the actual 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;
}
}
And change your code like this:
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);
}
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;
}
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;
}
Rather than write your own code, you can use an IntBuffer to wrap the existing int[] without having to copy the data into an Integer array:
int[] a = {1, 2, 3, 4};
IntBuffer b = IntBuffer.wrap(a);
IntBuffer implements comparable, so you are able to use the code you already have written. Formally, maps compare keys such that a.equals(b) is used to say two keys are equal, so two IntBuffers with array 1,2,3 - even if the arrays are in different memory locations - are said to be equal and so will work for your frequency code.
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);
}
}
This worked like a charm!
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);
Though the below compiles, it throws a ArrayStoreException at runtime.
Converting an int[], to an Integer[]:
int[] old;
...
Integer[] arr = new Integer[old.length];
System.arraycopy(old, 0, arr, 0, old.length);
I must admit I was a bit surprised that this compiles, given System.arraycopy being lowlevel and everything, but it does. At least in Java 7.
You can convert the other way just as easily.
I am not sure why you need a Double in your map. In terms of what you're trying to do, you have an int[] and you just want counts of how many times each sequence occurs(?). Why would this require a Double anyway?
I would create a wrapper for the int array with a proper .equals and .hashCode methods to account for the fact that int[] object itself doesn't consider the data in its version of these methods.
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;
}
}
And then use Google Guava's multiset, which is meant exactly for the purpose of counting occurrences, as long as the element type you put in it has proper .equals and .hashCode methods.
List<int[]> list = ...;
HashMultiset<IntArrayWrapper> multiset = HashMultiset.create();
for (int values[] : list) {
multiset.add(new IntArrayWrapper(values));
}
Then, to get the count for any particular combination:
int cnt = multiset.count(new IntArrayWrapper(new int[] { 0, 1, 2, 3 }));
Int is a primitive. Primitives can’t accept null and have default value. Hence, to accept Null you need to use wrapper class Integer.
Option 1:
int[] nos = { 1, 2, 3, 4, 5 };
Integer[] nosWrapped = Arrays.stream(nos)
.boxed()
.toArray(Integer[]::new);
nosWrapped[5] = null // can store null
Option 2:
You can use any data structure that use wrapper class Integer
int[] nos = { 1, 2, 3, 4, 5 };
List<Integer> = Arrays.asList(nos)
You don't need it. int[] is an object and can be used as a key inside a map.
Map<int[], Double> frequencies = new HashMap<int[], Double>();
is the proper definition of the frequencies map.
This was wrong :-). The proper solution is posted too :-).