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(",");
Related
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.
I have a stream of objects like this:
"0", "1", "2", "3", "4", "5",
How can I transform it to stream of pairs :
{ new Pair("0", "1"), new Pair("2", "3"), new Pair("4", "5")}.
The stream size is unknown. I am reading data from a file that might be big. I have only iterator to collection and I transform this iterator to stream using spliterator.
I know that here is a answer for processing adjacent pairs with StreamEx :
Collect successive pairs from a stream
Can this be done in java or StreamEx ?
Thanks
It's not a natural fit but you can do
List input = ...
List<Pair> pairs = IntStream.range(0, input.size() / 2)
.map(i -> i * 2)
.mapToObj(i -> new Pair(input.get(i), input.get(i + 1)))
.collect(Collectors.toList());
To create Pairs as you go in a stream you need a stateful lambdas which should be generally avoided but can be done. Note: this will only works if the stream is single threaded. i.e. not parallel.
Stream<?> stream =
assert !stream.isParallel();
Object[] last = { null };
List<Pair> pairs = stream.map(a -> {
if (last[0] == null) {
last[0] = a;
return null;
} else {
Object t = last[0];
last[0] = null;
return new Pair(t, a);
}
}).filter(p -> p != null)
.collect(Collectors.toList());
assert last[0] == null; // to check for an even number input.
If you don't want to collect the elements
The title of the question says collect pairs from a stream, so I'd assume that you want to actually collect these, but you commented:
Your solution works, the problem is that it loads the data from file to PairList and then I may use stream from this collection to process pairs. I can't do it because the data might be too big to store in the memory.
so here's a way to do this without collecting the elements.
It's relatively straightforward to transform an Iterator<T> into an Iterator<List<T>>, and from that to transform a stream into a stream of pairs.
/**
* Returns an iterator over pairs of elements returned by the iterator.
*
* #param iterator the base iterator
* #return the paired iterator
*/
public static <T> Iterator<List<T>> paired(Iterator<T> iterator) {
return new Iterator<List<T>>() {
#Override
public boolean hasNext() {
return iterator.hasNext();
}
#Override
public List<T> next() {
T first = iterator.next();
if (iterator.hasNext()) {
return Arrays.asList(first, iterator.next());
} else {
return Arrays.asList(first);
}
}
};
}
/**
* Returns an stream of pairs of elements from a stream.
*
* #param stream the base stream
* #return the pair stream
*/
public static <T> Stream<List<T>> paired(Stream<T> stream) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(paired(stream.iterator()), Spliterator.ORDERED),
false);
}
#Test
public void iteratorAndStreamsExample() {
List<String> strings = Arrays.asList("a", "b", "c", "d", "e", "f");
Iterator<List<String>> pairs = paired(strings.iterator());
while (pairs.hasNext()) {
System.out.println(pairs.next());
// [a, b]
// [c, d]
// [e, f]
}
paired(Stream.of(1, 2, 3, 4, 5, 6, 7, 8)).forEach(System.out::println);
// [1, 2]
// [3, 4]
// [5, 6]
// [7, 8]
}
If you want to collect the elements...
I'd do this by collecting into a list, and using an AbstractList to provide a view of the elements as pairs.
First, the PairList. This is a simple AbstractList wrapper around any list that has an even number of elements. (This could easily be adapted to handle odd length lists, once the desired behavior is specified.)
/**
* A view on a list of its elements as pairs.
*
* #param <T> the element type
*/
static class PairList<T> extends AbstractList<List<T>> {
private final List<T> elements;
/**
* Creates a new pair list.
*
* #param elements the elements
*
* #throws NullPointerException if elements is null
* #throws IllegalArgumentException if the length of elements is not even
*/
public PairList(List<T> elements) {
Objects.requireNonNull(elements, "elements must not be null");
this.elements = new ArrayList<>(elements);
if (this.elements.size() % 2 != 0) {
throw new IllegalArgumentException("number of elements must have even size");
}
}
#Override
public List<T> get(int index) {
return Arrays.asList(elements.get(index), elements.get(index + 1));
}
#Override
public int size() {
return elements.size() / 2;
}
}
Then we can define the collector that we need. This is essentially shorthand for collectingAndThen(toList(), PairList::new):
/**
* Returns a collector that collects to a pair list.
*
* #return the collector
*/
public static <E> Collector<E, ?, PairList<E>> toPairList() {
return Collectors.collectingAndThen(Collectors.toList(), PairList::new);
}
Note that it could be worthwhile defining a PairList constructor that doesn't defensively copy the list, for the use case that we know the backing list is freshly generated (as in this case). That's not really essential right now, though. But once we did that, this method would be collectingAndThen(toCollection(ArrayList::new), PairList::newNonDefensivelyCopiedPairList).
And now we can use it:
/**
* Creates a pair list with collectingAndThen, toList(), and PairList::new
*/
#Test
public void example() {
List<List<Integer>> intPairs = Stream.of(1, 2, 3, 4, 5, 6)
.collect(toPairList());
System.out.println(intPairs); // [[1, 2], [2, 3], [3, 4]]
List<List<String>> stringPairs = Stream.of("a", "b", "c", "d")
.collect(toPairList());
System.out.println(stringPairs); // [[a, b], [b, c]]
}
Here's a complete source file with a runnable example (as a JUnit test):
package ex;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
public class PairCollectors {
/**
* A view on a list of its elements as pairs.
*
* #param <T> the element type
*/
static class PairList<T> extends AbstractList<List<T>> {
private final List<T> elements;
/**
* Creates a new pair list.
*
* #param elements the elements
*
* #throws NullPointerException if elements is null
* #throws IllegalArgumentException if the length of elements is not even
*/
public PairList(List<T> elements) {
Objects.requireNonNull(elements, "elements must not be null");
this.elements = new ArrayList<>(elements);
if (this.elements.size() % 2 != 0) {
throw new IllegalArgumentException("number of elements must have even size");
}
}
#Override
public List<T> get(int index) {
return Arrays.asList(elements.get(index), elements.get(index + 1));
}
#Override
public int size() {
return elements.size() / 2;
}
}
/**
* Returns a collector that collects to a pair list.
*
* #return the collector
*/
public static <E> Collector<E, ?, PairList<E>> toPairList() {
return Collectors.collectingAndThen(Collectors.toList(), PairList::new);
}
/**
* Creates a pair list with collectingAndThen, toList(), and PairList::new
*/
#Test
public void example() {
List<List<Integer>> intPairs = Stream.of(1, 2, 3, 4, 5, 6)
.collect(toPairList());
System.out.println(intPairs); // [[1, 2], [2, 3], [3, 4]]
List<List<String>> stringPairs = Stream.of("a", "b", "c", "d")
.collect(toPairList());
System.out.println(stringPairs); // [[a, b], [b, c]]
}
}
Assuming there is a Pair with left, right and getters and a constructor:
static class Paired<T> extends AbstractSpliterator<Pair<T>> {
private List<T> list = new ArrayList<>(2);
private final Iterator<T> iter;
public Paired(Iterator<T> iter) {
super(Long.MAX_VALUE, 0);
this.iter = iter;
}
#Override
public boolean tryAdvance(Consumer<? super Pair<T>> consumer) {
getBothIfPossible(iter);
if (list.size() == 2) {
consumer.accept(new Pair<>(list.remove(0), list.remove(0)));
return true;
}
return false;
}
private void getBothIfPossible(Iterator<T> iter) {
while (iter.hasNext() && list.size() < 2) {
list.add(iter.next());
}
}
}
Usage would be:
Iterator<Integer> iterator = List.of(1, 2, 3, 4, 5).iterator();
Paired<Integer> p = new Paired<>(iterator);
StreamSupport.stream(p, false)
.forEach(pair -> System.out.println(pair.getLeft() + " " + pair.getRight()));
I know I'm late to the party, but all of the answers seem to be really complicated or have a lot of GC overhead/short-lived objects (which is not a big deal with modern JVMs), but why not do it simply like this?
public class PairCollaterTest extends TestCase {
static class PairCollater<T> implements Function<T, Stream<Pair<T, T>>> {
T prev;
#Override
public Stream<Pair<T, T>> apply(T curr) {
if (prev == null) {
prev = curr;
return Stream.empty();
}
try {
return Stream.of(Pair.of(prev, curr));
} finally {
prev = null;
}
}
}
public void testPairCollater() {
Stream.of("0", "1", "2", "3", "4", "5").sequential().flatMap(new PairCollater<>()).forEach(System.out::println);
}
}
Prints:
(0,1)
(2,3)
(4,5)
Just replace IntStream.range(1, 101) with your stream (you don't need to know your stream's size) -
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class TestClass {
public static void main(String[] args) {
final Pair pair = new Pair();
final List<Pair> pairList = new ArrayList<>();
IntStream.range(1, 101)
.map(i -> {
if (pair.a == null) {
pair.a = i;
return 0;
} else {
pair.b = i;
return 1;
}
})
.filter(i -> i == 1)
.forEach(i -> {
pairList.add(new Pair(pair));
pair.reset();
});
pairList.stream().forEach(p -> System.out.print(p + " "));
}
static class Pair {
public Object a;
public Object b;
public Pair() {
}
public Pair(Pair orig) {
this.a = orig.a;
this.b = orig.b;
}
void reset() {
a = null;
b = null;
}
#Override
public String toString() {
return "{" + a + "," + b + '}';
}
}
}
I have this code which is to check in the two arrays and print out the values that dont exist in the other array. I think the way i did it is not the most efficient way to do it hence can anyone offer a better OOP way to write this code in Java?
Thanks
public class Calculate {
static int [] x = {1,2,4,6,7};
static int [] y = {2,3,4,6,7};
static boolean xflag = true;
static boolean yflag = true;
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i = 0; i<x.length; i++)
{
for (int b=0; b<y.length; b++)
{
if(x[i]!= y[b])
{
xflag= false;
}
else
{
xflag = true;
break;
}
}
if(xflag==false)
{
System.out.println(x[i] +" does not exist in array 2");
}
}
for(int i = 0; i<x.length; i++)
{
for (int b=0; b<y.length; b++)
{
if(y[i]!= x[b])
{
yflag= false;
}
else
{
yflag = true;
break;
}
}
if(yflag==false)
{
System.out.println(y[i] +" does not exist in array1");
}
}
}
}
Using Collection class removeAll method
String original[] = { "1","2","3","4","6"};
String testStr[] = { "1","2","3","5","7" };
List origList = new ArrayList(Arrays.asList(original));
List testList = new ArrayList(Arrays.asList(testStr));
System.out.println(origList.removeAll(testList));
System.out.println(origList);
you can use java collection framework, Many function are there,
here is simple example check it.
public static void main(String a[]){
List<String> sl = new ArrayList<String>();
sl.add("apple");
sl.add("java");
sl.add("c++");
sl.add("unix");
sl.add("orange");
sl.add("airtel");
List<String> tl = new ArrayList<String>();
tl.add("job");
tl.add("oracle");
tl.add("jungle");
tl.add("cricket");
boolean isCommon = Collections.disjoint(sl,tl);
System.out.println("Does not found any common elements? "+isCommon);
tl.add("java");
isCommon = Collections.disjoint(sl,tl);
System.out.println("Does not found any common elements? "+isCommon);
}
You may use Apache's CollectionUtils for this purpose if you want an abstraction from the implementation logic.E.g:
public static void main(String[] args) {
List<Integer> list1=Arrays.asList(1,2,4,6,7);
List<Integer> list2=Arrays.asList(2,3,4,6,7);
System.out.println(CollectionUtils.disjunction(list1,list2));
}
You can code this way
List<Integer> array1 = Arrays.asList(1,2,4,6,7);
List<Integer> array2 = Arrays.asList(2,3,4,6,7);
List<Integer> disjointArray = new ArrayList<Integer>();
for (Integer value : array1) {
if (!array2.contains(value)) {
disjointArray.add(value);
}
}
And then you can print disjointArray or do whatever manipulation you want.
Here a running example using Javas Collection classes:
public class Disjunction {
public static void main(String args[]) throws UnsupportedEncodingException {
//Some data preparation
List<Integer> list1=Arrays.asList(1,2,4);
List<Integer> list2=Arrays.asList(5,2,8);
//Here calculating data1-data2 and data2-data1, collect all list items
//that are in data1 or in data2 but not in both.
List<Integer> data1 = new ArrayList<>(list1);
data1.removeAll(list2);
List<Integer> data2 = new ArrayList<>(list2);
data2.removeAll(list1);
//Merging both results. data1 contains now exclusive or of list1 and list2
data1.addAll(data2);
System.out.println("exclusive or is " + data1);
}
}
It prints out
exclusive or is [1, 4, 5, 8]
Try the following program that checks two arrays for numbers they both have and numbers they don't have:
package test;
import java.util.ArrayList;
public class ArrayDifferentiater {
public static void main(String[] args) {
int[] ori = { 1, 5, 4, 8, 6, 65, 16, 6, 575, 64, 561, 57, 57 };
int[] che = { 1, 4, 8, 6 };
sort(ori, che);
}
public static void sort(int[] a, int[] b) {
/**
* 'foundNum' contains the numbers which exists in both array.
* 'notFoundNum' contains the numbers which exists in only first array.
*/
ArrayList<Integer> foundNum = new ArrayList<>();
ArrayList<Integer> notFoundNum = new ArrayList<>();
// First for loop starts
for (int i = 0; i < a.length; i++) {
// Second for loop starts
for (int j = 0; j < b.length; j++) {
/**
* Check if array 1 contains value of array 2.
* If contains than add it to "foundNum" arraylist.
*/
if (a[i] == b[j]) {
foundNum.add(a[i]);
// Remove the number which exists in both arrays from "notFoundNum" arraylist.
if (notFoundNum.contains(a[i])) {
for (int k = 0; k < notFoundNum.size(); k++) {
if (notFoundNum.get(k) == a[i]) {
notFoundNum.remove(k);
}
}
}
break;
} // First if block ends
/**
* Checks if a not found number does not exists in 'notFoundNum' arraylist (to reduce redundancy)
* then adds a not found number to 'notFoundNum' arraylist
* */
if (!notFoundNum.contains(a[i]))
notFoundNum.add(a[i]);
} // Second for loop ends
} // First for loop ends
System.out.println("Found Numbers : " + foundNum);
System.out.println("Not Found Numbers : " + notFoundNum);
}
}
Here is the output for the above program:
Found Numbers : [1, 4, 8, 6, 6]
Not Found Numbers : [5, 65, 16, 575, 64, 561, 57]
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to concatenate two arrays in Java?
I have two objects
HealthMessage[] healthMessages1;
HealthMessage[] healthMessages2;
HealthMessage[] healthMessagesAll;
healthMessages1 = x.getHealth( );
healthMessages2 = y.getHealth( );
How should I join the two objects, so I can return only one:
return healthMessagesAll;
What's the recommended way?
Using Apache Commons Collections API is a good way:
healthMessagesAll = ArrayUtils.addAll(healthMessages1,healthMessages2);
I'd allocate an array with the total length of healthMessages1 and healthMessages2 and use System.arraycopy or two for loops to copy their contents. Here is a sample with System.arraycopy:
public class HelloWorld {
public static void main(String []args) {
int[] a = new int[] { 1, 2, 3};
int[] b = new int[] { 3, 4, 5};
int[] r = new int[a.length + b.length];
System.arraycopy(a, 0, r, 0, a.length);
System.arraycopy(b, 0, r, a.length, b.length);
// prints 1, 2, 3, 4, 5 on sep. lines
for(int x : r) {
System.out.println(x);
}
}
}
This is more intuitive to write and you don't have to deal with array indexes:
Collection<HealthMessage> collection = new ArrayList<HealthMessage>();
collection.addAll(Arrays.asList(healthMessages1));
collection.addAll(Arrays.asList(healthMessages2));
HealthMessage[] healthMessagesAll = collection.toArray(new HealthMessage[] {});
.. but don't ask me about it's performance in contrast to System.arraycopy.
I would go with System.arraycopy
private static HealthMessage[] join(HealthMessage[] healthMessages1, HealthMessage[] healthMessages2)
{
HealthMessage[] healthMessagesAll = new HealthMessage[healthMessages1.length + healthMessages2.length];
System.arraycopy(healthMessages1, 0, healthMessagesAll, 0, healthMessages1.length);
System.arraycopy(healthMessages2, 0, healthMessagesAll, healthMessages1.length, healthMessages2.length);
return healthMessagesAll;
}
Arrays are fixed length, so you have various alternatives. Here are a couple:
a) Create a new array with the size of the others and copy all the elements manually.
healthMessagesAll = new HealthMessage[healthMessages1.length + healthMessages2.length];
int i = 0;
for (HealthMessage msg : healthMessases1)
{
healthMessagesAll[i] = msg;
i++;
}
for (HealthMessage msg : healthMessages2)
{
healthMessagesAll[i] = msg;
i++;
}
b) Use the methods provided by the Arrays class. You can convert the array to a List, or copy elements around in bulk. Have a look at the functions it provides and choose the one that suits you.
UPDATE
Seeing your comment about duplicates. You might want to put everything in a Set which guarantees uniqueness. If you add the same element twice, it won't be added the second time.
You can then convert the Set back to an array if you explicitly require an array with its own toArray() method.
As suggested by other respondents, System.arraycopy() helps you copy the contents of the elements too, so its a shorter version of my alternative (a) above.
And for the most complex but least memory-hungry solution you can wrap them in an object. This one provides an Iterator<T> across all of the items and a copyTo method to copy to a new array. It could be easily enhanced to provide getters and setters.
public class JoinedArray<T> implements Iterable<T> {
final List<T[]> joined;
// Pass all arrays to be joined as constructor parameters.
public JoinedArray(T[]... arrays) {
joined = Arrays.asList(arrays);
}
// Iterate across all entries in all arrays (in sequence).
public Iterator<T> iterator() {
return new JoinedIterator<T>(joined);
}
private class JoinedIterator<T> implements Iterator<T> {
// The iterator across the arrays.
Iterator<T[]> i;
// The array I am working on. Equivalent to i.next without the hassle.
T[] a;
// Where we are in it.
int ai;
// The next T to return.
T next = null;
private JoinedIterator(List<T[]> joined) {
i = joined.iterator();
a = nextArray();
}
private T[] nextArray () {
ai = 0;
return i.hasNext() ? i.next() : null;
}
public boolean hasNext() {
if (next == null) {
// a goes to null at the end of i.
if (a != null) {
// End of a?
if (ai >= a.length) {
// Yes! Next i.
a = nextArray();
}
if (a != null) {
next = a[ai++];
}
}
}
return next != null;
}
public T next() {
T n = null;
if (hasNext()) {
// Give it to them.
n = next;
next = null;
} else {
// Not there!!
throw new NoSuchElementException();
}
return n;
}
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
}
public int copyTo(T[] to, int offset, int length) {
int copied = 0;
// Walk each of my arrays.
for (T[] a : joined) {
// All done if nothing left to copy.
if (length <= 0) {
break;
}
if (offset < a.length) {
// Copy up to the end or to the limit, whichever is the first.
int n = Math.min(a.length - offset, length);
System.arraycopy(a, offset, to, copied, n);
offset = 0;
copied += n;
length -= n;
} else {
// Skip this array completely.
offset -= a.length;
}
}
return copied;
}
public int copyTo(T[] to, int offset) {
return copyTo(to, offset, to.length);
}
public int copyTo(T[] to) {
return copyTo(to, 0);
}
#Override
public String toString() {
StringBuilder s = new StringBuilder();
Separator comma = new Separator(",");
for (T[] a : joined) {
s.append(comma.sep()).append(Arrays.toString(a));
}
return s.toString();
}
public static void main(String[] args) {
JoinedArray<String> a = new JoinedArray<String>(
new String[]{
"One"
},
new String[]{
"Two",
"Three",
"Four",
"Five"
},
new String[]{
"Six",
"Seven",
"Eight",
"Nine"
});
for (String s : a) {
System.out.println(s);
}
String[] four = new String[4];
int copied = a.copyTo(four, 3, 4);
System.out.println("Copied " + copied + " = " + Arrays.toString(four));
}
}
what about something along this way:
List<String> l1 = Arrays.asList(healthMessages1);
l1.addAll(Arrays.asList(healthMessages2));
HealthMessage[] result = l1.toArray();
(needs a bit of generification... :)