Outputs of the code is varies on iterating with Varargs.
Please let me know what is the reason for different outputs.
public class Demo {
public static void main(String[] args) {
Integer[] a = new Integer[]{1, 2, 3};
Integer[] b = new Integer[]{4, 5, 6};
List<Object> list1=new ArrayList<>();
addAllObj1(list1, a,b);
System.out.println(list1); //[[Ljava.lang.Integer;#24d46ca6, [Ljava.lang.Integer;#4517d9a3]
List<Object> list2=new ArrayList<>();
addAllObj2(list2, a,b);
System.out.println(list2); //[1, 2, 3, 4, 5, 6]
}
private static void addAllObj1(List<Object> list, Object[]... arr) {
for(Object o:arr) {
Collections.addAll(list, o);
}
}
private static void addAllObj2(List<Object> list, Object[]... arr) {
Collections.addAll(list, arr[0]);
Collections.addAll(list, arr[1]);
}
}
Thanks for your Help!
I am sorry for posting a wrong answer, but I think I found the solution now within the Java Specification. Here is how I understand it:
I think the following explains it:
private static void addAllObj2(List<Object> list, Object[]... arr) {
Object o = arr[0];
Collections.addAll(list, o);
Collections.addAll(list, arr[1]);
}
returns:
[[Ljava.lang.Integer;#75a1cd57, 4, 5, 6]
The line with index 1 does work, because during runtime, the jvm evaluates the arity parameters the the type of the input will not be rewritten The conversion to Integer apparently is possible. (I guess the type of b will not be changed)
In the line with index 0, the type will be evaluated and rewritten due to Type Erasure, as it will be stored as the Object o. The Type of the Object o and a (Integer[]) is not the same, therefore erasure takes place and it will be converted to an Object, hence the reference name.
This process apparently only takes place with arity parameters, as without:
public static void main(String[] args) {
List<Object> list3 = new ArrayList<>();
addAllObj3(list3, trePConcat(a, b));
System.out.println(list3);
}
private static void addAllObj3(List<Object> list, Object[] arr) {
Collections.addAll(list, arr[0]);
Collections.addAll(list, arr[1]);
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static Object[] trePConcat(Object[]... arr) {
return arr;
}
returns
[[Ljava.lang.Integer;#75a1cd57, [Ljava.lang.Integer;#3d012ddd]
Related
I am working on a problem to find which all combinations of integer in a given list can sum up to a given number.
public class SumProblem {
/*
* Input 2-2-3-7
* Output 2+2+3 and 7
*/
public static ArrayList<ArrayList<Integer>> find(ArrayList<Integer> input, int requiredSum) {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
find(result, requiredSum, 0, new ArrayList<>(), 0, input);
return result;
}
public static void find(ArrayList<ArrayList<Integer>> result , int requiredSum , int currentSum, ArrayList<Integer> partialResult, int i, ArrayList<Integer> input) {
if (currentSum == requiredSum ) {
ArrayList<Integer> temp = new ArrayList<>();
temp = (ArrayList<Integer>) partialResult.clone();
result.add(temp);
return;
}
if (i >= input.size()) {
return;
}
find(result, requiredSum, currentSum , partialResult, i +1, input );
partialResult.add(input.get(i));
find(result, requiredSum, currentSum + input.get(i) , partialResult, i +1, input );
}
public static void main(String[] args) {
ArrayList<Integer> input = new ArrayList<>();
input.add(2);
input.add(1);
input.add(3);
ArrayList<ArrayList<Integer>> output = find(input, 3);
System.out.println(output.toString());
}
}
I have written code below.
I am facing one problem. In the below line of code, it is adding up all the numbers i traverse even if i create new ArrayList object and assign it to partialResult.
partialResult.add(input.get(i));
Could anyone suggest the solution ?
You have two recursive calls in this dynamic programming solution to the problem. One is supposed to not include the current value in the result, the other does.
You need to make a defensive copy of partialResult, otherwise both recursive calls are going to have a reference to the same list. A list is a mutable object. If both calls get a reference to the same list object, then when you add something to it anywhere, both of them will see the modified list.
The easiest way to make a defensive copy of a list is just to write:
new ArrayList<>(partialResult)
Here is a working version of the program:
import java.util.*;
public class SumProblem {
public static List<List<Integer>> find(List<Integer> input, int requiredSum) {
List<List<Integer>> result = new ArrayList<>();
find(result, requiredSum, 0, new ArrayList<>(), 0, input);
return result;
}
public static void find(List<List<Integer>> result, int requiredSum, int currentSum,
List<Integer> partialResult, int i, List<Integer> input) {
if (currentSum == requiredSum) {
result.add(new ArrayList<>(partialResult)); // add a copy of the list
return;
}
if (i >= input.size()) {
return;
}
// make defensive copies in the recursive calls
find(result, requiredSum, currentSum, new ArrayList<>(partialResult), i + 1, input);
partialResult.add(input.get(i));
find(result, requiredSum, currentSum + input.get(i), new ArrayList<>(partialResult), i + 1, input);
}
public static void main(String[] args) {
List<Integer> input = List.of(2, 8, 2, 3, 4);
List<List<Integer>> output = find(input, 7);
System.out.println(output);
}
}
Output:
[[3, 4], [2, 2, 3]]
I've made a few other changes:
Use List<Integer> and List<List<Integer>> as the types (code to the interface)
Use List.of() to create the input list (added in Java 9)
Don't call toString() on objects passed to println — it's unneeded
import java.util.*;
public class ArrayList5 {
static int max(ArrayList list) { // to be completed
if (list.size() == 0) {
return 0;
}
else
{
int first = (Integer) list.get(0);
list.remove(0);
if (first > max(new ArrayList(list)))
{
return first;
}
else
{
return max(list);
}
}
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
Collections.addAll(list, 4, 5, 3, 2, 3, 1, 3);
// int t=Console.readInt("Enter Target:");
int res1 = max(new ArrayList(list));
System.out.println("max=" + res1);
}
}
I don't understand why the max(new ArrayList(list))) part is required. Why does it have to create a new one and why can't it continue to work with the one list?
Also why doesn't it get caught in a loop (it's recursion so it will keep sending up a new list so I don't understand why 'first' isn't going to be 4 every time)?
Actually, there is a lot of superfluous code that is not required and make the code cumbersome/more difficult to read/understand.
You can simplify the code a lot and get rid of any reference to ArrayList which are not really necessary and by using proper generic at the right places, make the code actually readable.
You don't need to cast or create list all over the place.
public class ArrayList5 {
static int max(final List<Integer> list) {
if(list.isEmpty()) return 0;
final int head = list.get(0);
final List<Integer> tail = list.subList(1, list.size());
return (head > max(tail)? head:max(tail));
}
public static void main(final String... args) {
final int res1 = max(Arrays.asList(4, 5, 3, 2, 3, 1, 3));
System.out.printf("max=%d", res1);
}
}
You should try this:
static int max(ArrayList<Integer> list) {...}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
Collections.addAll(list, 4, 5, 3, 2, 3, 1, 3);
// int t=Console.readInt("Enter Target:");
int res1 = max(new ArrayList(list));
System.out.println("max=" + res1);
}
The compiler is probably throws a warning because you don't declare the type of the ArrayList.
import java.util.ArrayList;
public class bugs
{
public ArrayList<Integer> elements1;
public ArrayList<Integer> elements2;
public bugs(ArrayList<Integer> args)
{
elements1 = args;
elements2 = args;
}
public void change(int index, int value)
{
elements1.set(index, value);
}
public void reset()
{
elements1 = elements2;
}
public static void main(String[] a)
{
ArrayList<Integer> stuff = new ArrayList<Integer>();
stuff.add(1);
stuff.add(1);
stuff.add(1);
stuff.add(1);
bugs b = new bugs(stuff);
b.change(2, 999);
b.reset();
System.out.println(b.elements2);
}
}
This outputs:
[1, 1, 999, 1]
The second arraylist elements2 is there to reset the arraylist elements1 to its original position. However, for some reason elements1 is being copied to elements2, printing
[1, 1, 999, 1]
and not
[1, 1, 1, 1]
You are passing the same ArrayList reference to both variables.
What you meant to do is:
public bugs(ArrayList<Integer> args)
{
elements1 = new ArrayList<Integer>(args);
elements2 = new ArrayList<Integer>(args);
}
EDIT:
Note that this is only a temporary fix. Calling reset() will pass the reference of elements2 to elements1 and then you have the same situation. If you create a new arraylist and you pass another list as argument, you create a new reference with the same contents. This means you must also adjust your reset() method to create a new list and pass elements2 as argument.
In java you can pass by reference or by value. If you are using primitive data types, you are passing by value. So:
public void method(int num)
{
int num1 = num;
int num2 = num;
}
This method pass num value to num1 and num2 primitive data types. If you add something to num1 it will not change num2 to the same value. But if you are using non primitive data types like ArrayList:
public bugs(ArrayList<Integer> args)
{
elements1 = args;
elements2 = args;
}
You should expect that change in elements1 array will change elements2 array also. In this example you are passing the same ArrayList reference to both variables.
The solution for your problem is create copy of your arrays:
public bugs(ArrayList<Integer> args)
{
elements1 = new ArrayList<>(args);
elements2 = new ArrayList<>(args);
}
public void reset()
{
elements1 = new ArrayList<>(elements2);
}
I want to flatten nested arrays like:
[[[1],2],[3]],4] -> [1,2,3,4]
manually in java I can't find a clue ! :S
I have tried a manual java script guide but it doesn't get a solution
public static void main(String[] args) {
Object arr[] = { 1, 2, new Object[] { 4, new int[] { 5, 6 }, 7 }, 10 };
String deepToString = Arrays.deepToString(arr);
String replace = deepToString.replace("[", "").replace("]", "");
String array[] = replace.split(",");
int temp[] = new int[array.length];
for (int i = 0; i < array.length; i++) {
temp[i] = Integer.parseInt(array[i].trim());
}
System.out.println(Arrays.toString(temp));
}
The Stream API offers a compact and flexible solution. Using the method
private static Stream<Object> flatten(Object[] array) {
return Arrays.stream(array)
.flatMap(o -> o instanceof Object[] a? flatten(a): Stream.of(o));
}
or prior to JDK 16
private static Stream<Object> flatten(Object[] array) {
return Arrays.stream(array)
.flatMap(o -> o instanceof Object[]? flatten((Object[])o): Stream.of(o));
}
you can perform the operation as
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10 };
System.out.println("original: "+Arrays.deepToString(array));
Object[] flat = flatten(array).toArray();
System.out.println("flat: "+Arrays.toString(flat));
or when you assume the leaf objects to be of a specific type:
int[] flatInt = flatten(array).mapToInt(Integer.class::cast).toArray();
System.out.println("flat int: "+Arrays.toString(flatInt));
I created a class to solve this using Java, the code is also shown below.
Solution:
package com.conorgriffin.flattener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Flattens an array of arbitrarily nested arrays of integers into a flat array of integers.
* <p/>
* #author conorgriffin
*/
public class IntegerArrayFlattener {
/**
* Flatten an array of arbitrarily nested arrays of integers into a flat array of integers. e.g. [[1,2,[3]],4] -> [1,2,3,4].
*
* #param inputArray an array of Integers or nested arrays of Integers
* #return flattened array of Integers or null if input is null
* #throws IllegalArgumentException
*/
public static Integer[] flatten(Object[] inputArray) throws IllegalArgumentException {
if (inputArray == null) return null;
List<Integer> flatList = new ArrayList<Integer>();
for (Object element : inputArray) {
if (element instanceof Integer) {
flatList.add((Integer) element);
} else if (element instanceof Object[]) {
flatList.addAll(Arrays.asList(flatten((Object[]) element)));
} else {
throw new IllegalArgumentException("Input must be an array of Integers or nested arrays of Integers");
}
}
return flatList.toArray(new Integer[flatList.size()]);
}
}
Unit Tests:
package com.conorgriffin.flattener;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests IntegerArrayFlattener
*/
public class IntegerArrayFlattenerTest {
Integer[] expectedArray = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
#Test
public void testNullReturnsNull() throws IllegalArgumentException {
Assert.assertNull(
"Testing a null argument",
IntegerArrayFlattener.flatten(null)
);
}
#Test
public void testEmptyArray() throws IllegalArgumentException {
Assert.assertArrayEquals(
"Testing an empty array",
new Integer[]{},
IntegerArrayFlattener.flatten(new Object[]{})
);
}
#Test
public void testFlatArray() throws IllegalArgumentException {
Assert.assertArrayEquals(
"Testing a flat array",
expectedArray,
IntegerArrayFlattener.flatten(new Object[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
);
}
#Test
public void testNestedArray() throws IllegalArgumentException {
Assert.assertArrayEquals(
"Testing nested array",
expectedArray,
IntegerArrayFlattener.flatten(new Object[]{1, 2, 3, 4, new Object[]{5, 6, 7, 8}, 9, 10})
);
}
#Test
public void testMultipleNestedArrays() throws IllegalArgumentException {
Assert.assertArrayEquals(
"Testing multiple nested arrays",
expectedArray,
IntegerArrayFlattener.flatten(new Object[]{1, 2, new Object[]{3, 4, new Object[]{5}, 6, 7}, 8, 9, 10})
);
}
#Test(expected = IllegalArgumentException.class)
public void throwsExceptionForObjectInArray() throws IllegalArgumentException {
IntegerArrayFlattener.flatten(
new Object[]{new Object()}
);
}
#Test(expected = IllegalArgumentException.class)
public void throwsExceptionForObjectInNestedArray() throws IllegalArgumentException {
IntegerArrayFlattener.flatten(
new Object[]{1, 2, new Object[]{3, new Object()}}
);
}
#Test(expected = IllegalArgumentException.class)
public void throwsExceptionForNullInArray() throws IllegalArgumentException {
IntegerArrayFlattener.flatten(
new Object[]{null}
);
}
#Test(expected = IllegalArgumentException.class)
public void throwsExceptionForNullInNestedArray() throws IllegalArgumentException {
IntegerArrayFlattener.flatten(
new Object[]{1, 2, new Object[]{3, null}}
);
}
}
If it's a primitive array with only two levels, you could do:
Arrays.stream(array)
.flatMapToInt(o -> Arrays.stream(o))
.toArray()
to get the corresponding boxed array (which you can unbox if necessary)
That's the way I would solve it.
Don't know which kind of efficiency you are looking for. But yeah. that does the job in JavaScript.
arr.toString().split(',').filter((item) => item).map((item) => Number(item))
A probably more efficient way to do this would be to use reduce and concat method from arr and recursion.
function flattenDeep(arr1) {
return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
This is how I solved this problem in Java:
public class ArrayUtil {
/**
* Utility to flatten an array of arbitrarily nested arrays of integers into
* a flat array of integers. e.g. [[1,2,[3]],4] -> [1,2,3,4]
* #param inputList
*/
public static Integer[] flattenArray(ArrayList<Object> inputList) {
ArrayList<Integer> flatten = new ArrayList<Integer>();
if (inputList.size() <= 0) {
return new Integer[0]; // if the inputList is empty, return an empty Integer[] array.
}
for (Object obj : inputList) {
recursiveFlatten(flatten, obj); // otherwise we can recursively flatten the input list.
}
Integer [] flatArray = new Integer[flatten.size()];
return flatArray = flatten.toArray(flatArray);
}
/**
* Recursively flatten a nested array.
* #param flatten
* #param o
*/
private static void recursiveFlatten(ArrayList<Integer> flatten, Object o){
if(isInteger(o)){ // if the object is of type Integer, just add it into the list.
flatten.add((Integer)o);
} else if(o instanceof ArrayList){ // otherwise, we need to call to recursively flatten the array
for(Object obj : (ArrayList<Object>) o){ // for the case where there are deeply nested arrays.
recursiveFlatten(flatten, obj);
}
}
}
/**
* Return true if object belongs to Integer class,
* else return false.
* #param obj
* #return
*/
private static boolean isInteger(Object obj) {
return obj instanceof Integer;
}
}
It could be flattened by iterative approach.
static class ArrayHolder implements Iterator<Object> {
private final Object[] elements;
private int index = -1;
public ArrayHolder(final Object[] elements) {
this.elements = elements;
}
#Override
public boolean hasNext() {
return Objects.nonNull(elements) && ++index < elements.length;
}
#Override
public Object next() {
if (Objects.isNull(elements) || (index == -1 || index > elements.length))
throw new NoSuchElementException();
return elements[index];
}
}
private static boolean hasNext(ArrayHolder current) {
return Objects.nonNull(current) && current.hasNext();
}
private void flat(Object[] elements, List<Object> flattened) {
Deque<ArrayHolder> stack = new LinkedList<>();
stack.push(new ArrayHolder(elements));
ArrayHolder current = null;
while (hasNext(current)
|| (!stack.isEmpty() && hasNext(current = stack.pop()))) {
Object element = current.next();
if (Objects.nonNull(element) && element.getClass().isArray()) {
Object[] e = (Object[]) element;
stack.push(current);
stack.push(new ArrayHolder(e));
current = null;
} else {
flattened.add(element);
}
}
}
You can find the full source here
You can use recursion to solve this problem.
private void flat(Object[] elements, List<Object> flattened) {
for (Object element : elements)
{
if (Objects.nonNull(element) && element.getClass().isArray())
{
flat((Object[])element, flattened);
}
else
{
flattened.add(element);
}
}
}
Here is the link for recursion.
The recursive call approach will work for this case:
private static void recursiveCall(Object[] array) {
for (int i=0;i<array.length;i++) {
if (array[i] instanceof Object[]) {
recursiveCall((Object[]) array[i]);
}else {
System.out.println(array[i]);
}
}
}
package com.app;
import java.util.Arrays;
public class Test2 {
public static void main(String[] args) {
Object arr[] = { 1, 2, new Object[] { 4, new int[] { 5, 6 }, 7 }, 10 };
String deepToString = Arrays.deepToString(arr);
String replace = deepToString.replace("[", "").replace("]", "");
String array[] = replace.split(",");
int temp[] = new int[array.length];
for (int i = 0; i < array.length; i++) {
temp[i] = Integer.parseInt(array[i].trim());
}
System.out.println(Arrays.toString(temp));
}
}
you can try this code:
String a = "[[[1],2],[3]],4] ";
a= a.replaceAll("[(\\[|\\])]", "");
String[] b = a.split(",");
Using the public boolean contains(Object o) in the ArrayList library does not work in this case. Consider
ArrayList<int[][]> test = new ArrayList<>();
int[][] one = {
{1,2,3},
{4,5,6}
};
int[][] two = {
{1,2,3},
{4,5,6}
};
int[][] three = {
{9,7,5},
{1,2,4},
{5,6,7}
};
test.add(one);
System.out.println(test.contains(one));
System.out.println(test.contains(two));
System.out.println(test.contains(three));
The above code returns
true
false
false
Is there a way to check for equality between the two and make sure that no duplicate values enter the list?
The easiest approach I know is to extract it into a method using Arrays.deepEquals(Object[], Object[]), something like -
public static boolean contains(List<int[][]> al, int[][] toFind) {
for (int[][] arr : al) {
if (Arrays.deepEquals(arr, toFind)) {
return true;
}
}
return false;
}
Then you can test it like
public static void main(String[] args) {
ArrayList<int[][]> test = new ArrayList<int[][]>();
int[][] one = { { 1, 2, 3 }, { 4, 5, 6 } };
int[][] two = { { 1, 2, 3 }, { 4, 5, 6 } };
int[][] three = { { 9, 7, 5 }, { 1, 2, 4 }, { 5, 6, 7 } };
test.add(one);
if (contains(test, two)) {
System.out.println("Found two");
}
}
Output is
Found two
One solution would be to wrap the arrays in a class that provides an appropriate equals implementation.
class SquareArray {
private int[][] array;
public SquareArray(int[][] array) {
this.array = array;
}
public int[][] getArray() {
return array;
}
#Override
public boolean equals(Object o) {
return (o instanceof SquareArray) &&
Arrays.deepEquals(array, ((SquareArray)o).array);
}
#Override
public int hashCode() {
return Arrays.deepHashCode(array);
}
#Override
public String toString() {
return Arrays.deepToString(array);
}
}
Now you would use a List<SquareArray>; for instance:
int[][] a = {{1,2,3}, {4,5,6}};
int[][] b = {{1,2},{3,4},{5,6}};
int[][] c = {{1,2,3}, {4,5,6}};
SquareArray x = new SquareArray(a);
SquareArray y = new SquareArray(b);
SquareArray z = new SquareArray(c);
List<SquareArray> list = new ArrayList<>();
list.add(x);
System.out.println(list.contains(x));
System.out.println(list.contains(y));
System.out.println(list.contains(z));
true
false
true
Reference:
Arrays.deepEquals
Arrays.deepHashCode
Arrays.deepToString
I'd like to propose another solution using Java 8 streams and predicates:
The Stream#anyMatch method may be used to check whether the given list contains a certain element. The required predicate can be build concisely using Arrays#deepEquals:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GenericContainsTest
{
public static void main(String[] args)
{
List<int[][]> list = new ArrayList<int[][]>();
int[][] one =
{ { 1, 2, 3 },
{ 4, 5, 6 } };
int[][] two =
{ { 1, 2, 3 },
{ 4, 5, 6 } };
list.add(one);
if (list.stream().anyMatch(e->Arrays.deepEquals(e, two)))
{
System.out.println("Found two");
}
}
}
However, you mentioned that your intention is to...
... make sure that no duplicate values enter the list
In this case, you should at least consider to not use a List, but a Set - particularly, a Set<SquareArray> using the SquareArray class that arashajii proposed in his answer.
contains method use the method equals(e) and when you use equals on array it's the same thing as using == hence you check for reference equality, not content.
To check if two arrays are equals you have to use Arrays.equals(array1, array2) or Arrays.deepEquals(nestedArray1, nestedArray2) for nested arrays.