This question already has answers here:
Flatten nested arrays in java
(9 answers)
Closed 3 months ago.
This question was asked to me in Razorpay. I could not come up with a solution. Can anyone help me in writing Java code for this.
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10};
Answer should be:
Integer[] = {1,2,3,4,5,6,7,8,9,10};
i.e. all the Integer elements should be stored
What I did is
for(Object obj: array){
if(obj instanceof Integer) list.add((int)(obj));
}
Which results in -> 1,2,8,9,10. How do I add 3,4,5,6,7 inside list?
As there's no finite depth of nesting of Object[] you'll need a recursive approach:
import java.util.ArrayList;
import java.util.List;
public class Answer {
static void extractIntegers(Object[] source, List<Integer> destination) {
for (Object i : source) {
if (i instanceof Object[] array) {
extractIntegers(array, destination);
} else if (i instanceof Integer integer) {
destination.add(integer);
} else {
throw new IllegalArgumentException("Unexpected: " + i);
}
}
}
public static void main(String[] args) {
List<Integer> ints = new ArrayList<>();
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10};
extractIntegers(array, ints);
System.out.println(ints);
}
}
Note that I'm using the recently added "pattern matching for instanceof" feature of Java.
You could ignore objects which are not Object[] or Integer. I've chosen to throw an excpetion.
The operation you are looking for is called flattening an array. Your input is an array of Object which can consist of either Integer or Object[]. So we have to handle both cases here, and it is easier done with recursion:
Write a function flatten(Object[] arr) that takes in an Object[] as parameter. The function will return List<Integer> which is the result after arr is flattened.
The logic is simple for the recursive flatten() function:
create empty result_array
for each obj in Object[]:
if obj is an Integer:
add obj to the result_array
else obj is Object[]:
flat_obj := flatten(obj)
add all integers of flat_obj into result_array
return result_array
Here are the Java code for the above logic implemented. Hope it helps!
public class Test {
public static List<Integer> flatten(Object[] array) {
List<Integer> result = new ArrayList<>();
for (Object o: array) {
if (o instanceof Object[])
result.addAll( flatten( (Object[]) o) );
else
result.add((Integer) o);
}
return result;
}
public static void main(String[] args) {
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10};
System.out.println( flatten(array) );
}
}
You're only checking for integers, but you also have arrays in your array.
Together with the instanceof Integer check, you should also add a check on instanceof Object[]. Be careful that also the Object[] contains an Object[]. So you'll have to have the same check inside of it as well. You shall have 3 loops in the end, each of which will have checks on instanceof Integer and instanceof Object[]
Related
Problem
I have a task that reads as follows:
Implement an IntegerList class with a Vector list object attribute that contains a collection of integers. Implement the findMedian () method which, for a given object from o of the IntegerList class, returns a number m from the vector o.list such that there are at least half of the numbers less than or equal to m, and the numbers greater than or equal to m are also at least half:
For example, for [1, 4, 1, 3, 5, 7] it will be the number 4, and for [1, 1, 1, 2, 2] it will be the number 1 and only 1. If the vector is empty then the method is supposed to throw an IllegalArgumentException exception.
What I tried?
import java.util.Vector;
public class IntegerList {
Vector<Integer> list =new Vector<Integer>();
public int findMedian(Vector<Integer>list){
if(list.size() ==0){
throw new IllegalArgumentException();
}
int result =0;
return result;
}
}
public class Main {
public static void main(String[] args){
IntegerList v = new IntegerList();
v.list.add(2);
v.list.add(3);
v.list.add(4);
v.list.add(9);
System.out.println(v.findMedian(v.list));
}
}
My question:
Why this not working?
What would you change to even better solve this problem?
It is working, but only on empty list. To make it work: we should apply what we learned ..and little try.
Voila:
public int findMedian(Vector<Integer> list) {
if (list == null || list.isEmpty()) {
throw new IllegalArgumentException("'list' is null or empty");
} // from here: list not null and list.size() > 0 ... :
// sort the "list":
java.util.Collections.sort(list); // if you may not modify the list: create a copy first! (the list remains sorted, also when leaving the method...
// return "middle" element:
return list.get(list.size()/2);
}
javadoc
I am trying to create a method that will recursively reverse an ArrayList of generics, and am running into issues with the declaration of my reversedList array (see line 4 of code below).
As the code stands, I receive the error:
cannot find symbol Class: E
The only way I have found to stop the error is by declaring reversedList inside the method, but then it will reset every time it recurses.
import java.util.ArrayList;
import java.util.List;
public class ListRecursive<E>{
public static List<E> reversedList= new ArrayList<E>();
public static <E> void reverse(ArrayList<E> inputList){
E firstitem = null;
if (inputList.size() == 0 ) {
return;
}
else {
firstitem = inputList.get(0);
inputList.remove(0);
}
reverse(inputList);
reversedList.add( firstitem );
}
Below is the main method, which creates an ArrayList of commmand line arguments and attempts to reverse it using the method above.
public static void main(String args[]){
ArrayList<String> argList = new ArrayList<>();
ArrayList<Double> numericArgs = new ArrayList<>();
for (String s : args) {
argList.add(s);
try {
numericArgs.add(Double.parseDouble(s));
}
catch (NumberFormatException e) {
System.out.println(e.getMessage() + "is not numeric...skipping");
}
}
System.out.print("Command line arguments before reversal: ");
for (int i=0; i<argList.size(); i++)
System.out.print(argList.get(i)+ " ");
System.out.println();
reverse(argList);
System.out.print("Command line arguments afterreversal: ");
for (int i=0; i<argList.size(); i++)
System.out.print(argList.get(i)+ " ");
System.out.println();
}
Presuming that you.
Wanted to do it recursively
Didn't want to destroy the original list.
And didn't want to allocate the new List external to the method.
You can do the following:
public static <E> List<E> reverse(List<E> inputList) {
List<E> ret = new ArrayList<>();
E o = inputList.remove(0);
if (inputList.size() > 0) {
ret = reverse(inputList);
}
// at this point they will be on the stack in reverse order.
// so add them to the stack in that order.
ret.add(o);
// return the orginal list to its initial state by inserting them at the beginning.
inputList.add(0, o);
return ret;
}
Calling with this.
List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
System.out.println(reverse(ints));
System.out.println(ints);
Produces this output.
[5, 4, 3, 2, 1]
[1, 2, 3, 4, 5]
A non-recursive solution would be, of course, trivial.
Note: The passed List must support List.remove() and be mutable for this to work. If you declare your list using List.of() or Arrays.asList() you must pass your list as an argument to the ArrayList<>() constructor.
First of all, if it's a utility method, why store the parameter, if not, then why is it static. You also don't need multiple instances, as method parameters in java are pass-by-reference. More importantly, recursive means your list will be limited to your call stack limit.
Try It Online
public static <E> void reverse(List<E> list) {
for (int i=0;i<list.size()/2;i++) {
E temp = list.get(i);
list.set(i, list.get(list.size()-i-1));
list.set(list.size()-i-1, temp);
}
}
This is the follow up of compare sets
I have
Set<Set<Node>> NestedSet = new HashSet<Set<Node>>();
[[Node[0], Node[1], Node[2]], [Node[0], Node[2], Node[6]], [Node[3], Node[4], Node[5]] [Node[2], Node[6], Node[7]] ]
I want to merge the sets when there are two elements in common. For example 0,1,2 and 0,2,6 has two elements in common so merging them to form [0,1,2,6].
Again [0,1,2,6] and [2,6,7] has 2 and 6 common. so merging them and getting [0,1,2,6,7].
The final output should be :
[ [Node[0], Node[1], Node[2], Node[6], Node[7]], [Node[3], Node[4], Node[5]] ]
I tried like this :
for (Set<Node> s1 : NestedSet ) {
Optional<Set<Node>> findFirst = result.stream().filter(p -> { HashSet<Node> temp = new HashSet<>(s1);
temp.retainAll(p);
return temp.size() == 2; }).findFirst();
if (findFirst.isPresent()){
findFirst.get().addAll(s1);
}
else {
result.add(s1);
}
}
But the result I got was :
[[Node[0], Node[1], Node[2], Node[6], Node[7]], [Node[3], Node[4], Node[5]], [Node[0], Node[2], Node[6], Node[7]]]
Any idea ? Is there any way to get the desired output?
Some considerations:
Each time you apply a merge, you have to restart the procedure and iterate over the modified collection. Because of this, the iteration order of the input set is important, if you want your code to be deterministic you may want to use collections that give guarantees over their iteration order (e.g. use LinkedHashSet (not HashSet) or List.
Your current code has side effects as it modifies the supplied sets when merging. In general I think it helps to abstain from creating side effects whenever possible.
The following code does what you want:
static <T> List<Set<T>> mergeSets(Collection<? extends Set<T>> unmergedSets) {
final List<Set<T>> mergedSets = new ArrayList<>(unmergedSets);
List<Integer> mergeCandidate = Collections.emptyList();
do {
mergeCandidate = findMergeCandidate(mergedSets);
// apply the merge
if (!mergeCandidate.isEmpty()) {
// gather the sets to merge
final Set<T> mergedSet = Sets.union(
mergedSets.get(mergeCandidate.get(0)),
mergedSets.get(mergeCandidate.get(1)));
// removes both sets using their index, starts with the highest index
mergedSets.remove(mergeCandidate.get(0).intValue());
mergedSets.remove(mergeCandidate.get(1).intValue());
// add the mergedSet
mergedSets.add(mergedSet);
}
} while (!mergeCandidate.isEmpty());
return mergedSets;
}
// O(n^2/2)
static <T> List<Integer> findMergeCandidate(List<Set<T>> sets) {
for (int i = 0; i < sets.size(); i++) {
for (int j = i + 1; j < sets.size(); j++) {
if (Sets.intersection(sets.get(i), sets.get(j)).size() == 2) {
return Arrays.asList(j, i);
}
}
}
return Collections.emptyList();
}
For testing this method I created two helper methods:
static Set<Integer> set(int... ints) {
return new LinkedHashSet<>(Ints.asList(ints));
}
#SafeVarargs
static <T> Set<Set<T>> sets(Set<T>... sets) {
return new LinkedHashSet<>(Arrays.asList(sets));
}
These helper methods allow to write very readable tests, for example (using the numbers from the question):
public static void main(String[] args) {
// prints [[2, 6, 7, 0, 1]]
System.out.println(mergeSets(sets(set(0, 1, 2, 6), set(2, 6, 7))));
// prints [[3, 4, 5], [0, 2, 6, 1, 7]]
System.out.println(
mergeSets(sets(set(0, 1, 2), set(0, 2, 6), set(3, 4, 5), set(2, 6, 7))));
}
I'm not sure why you are getting that result, but I do see another problem with this code: It is order-dependent. For example, even if the code worked as intended, it would matter whether [Node[0], Node[1], Node[2]] is compared first to [Node[0], Node[2], Node[6]] or [Node[2], Node[6], Node[7]]. But Sets don't have a defined order, so the result is either non-deterministic or implementation-dependent, depending on how you look at it.
If you really want deterministic order-dependent operations here, you should be using List<Set<Node>>, rather than Set<Set<Node>>.
Here's a clean approach using recursion:
public static <T> Set<Set<T>> mergeIntersectingSets(Collection<? extends Set<T>> unmergedSets) {
boolean edited = false;
Set<Set<T>> mergedSets = new HashSet<>();
for (Set<T> subset1 : unmergedSets) {
boolean merged = false;
// if at least one element is contained in another subset, then merge the subsets
for (Set<T> subset2 : mergedSets) {
if (!Collections.disjoint(subset1, subset2)) {
subset2.addAll(subset1);
merged = true;
edited = true;
}
}
// otherwise, add the current subset as a new subset
if (!merged) mergedSets.add(subset1);
}
if (edited) return mergeIntersectingSets(mergedSets); // continue merging until we reach a fixpoint
else return mergedSets;
}
I have to find a best way to find out that elements which is not presented in the second arraylist.
suppose
Arraylist a,b,
Arraylist a={1,2,3,4,5};
Arraylist b={2,3,4};
So basically what I want is to find out that elements of a which is not present in arraylist b.
So what is the best solutions to do that?
List<Integer> c = new ArrayList<>(a);
c.removeAll(b);
Also consider to use Sets instead of Lists.
here is another approach using java 8 -
a.stream().filter(b::contains).collect(Collectors.toList());
You could use Apache Commons Collections, which has a method explicitly for this purpose:
public static void main(String[] args) {
List<Integer> a = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
List<Integer> b = Arrays.asList(new Integer[] { 2, 3, 4 });
Collection<Integer> aMinusB = CollectionUtils.subtract(a, b);
System.out.println(aMinusB);
}
The printed result is: [1, 5].
The Apache Commons libs are well tested and commonly used to extend standard Java functionalities. This particular method accepts Iterable as parameters, so you can use any Collection you want. You can also mix different collection types:
public static void main(String[] args) {
List<Integer> a = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
Set<Integer> b = new HashSet<Integer>(Arrays.asList(new Integer[] { 2, 3, 4 }));
Collection<Integer> aMinusB = CollectionUtils.subtract(a, b);
System.out.println(aMinusB);
}
The printed result is the same, [1, 5].
Check out the Javadoc here.
For sake of completeness, Google's Guava library does not have this feature:
Collection *subtract*(Collection, Collection)
No equivalent--create an ArrayList containing a and then call remove on it for each element in b.
However, it implements a method called Sets.difference() method, which you could use if you prefer Guava and work with sets:
public static void main(String[] args) {
Set<Integer> a = new HashSet<Integer>(Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 }));
Set<Integer> b = new HashSet<Integer>(Arrays.asList(new Integer[] { 2, 3, 4 }));
Set<Integer> aMinusB = Sets.difference(a, b);
System.out.println(aMinusB);
}
The result is all elements in a that doesn't exist in b (i.e. [1, 5] again). Of course, the order is not determined since it operates on sets.
You can try removeAll:
List<Integer> notPresent = new ArrayList<Integer>(a);
notPresent.removeAll(b);
Use org.apache.commons.collections4.ListUtils
Given
List<Integer> a = Arrays.asList(new Integer[]{ 1,2,3,4,5});
List<Integer> b = Arrays.asList(new Integer[]{0,1,2,3});
Action
List<Integer> c = ListUtils.removeAll(b, a)
Result in List c
4, 5
Please try like this
for (Object o : a) {
if (!b.contains(o)) {
// this is not present
}
}
Loop through one list, then check if each element in other list using contains.
Something like this. If you think there may be duplicates in a you can try another type of Collection, like a Set for notPresent.
List<Integer> notPresent = new ArrayList<Integer>();
for (Integer n : a){
if (!b.contains(n)){
notPresent.add(n);
}
}
Try this:
public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
List<Integer> b = new ArrayList<Integer>();
List<Integer> exclusion = new ArrayList<Integer>();
a.add(1);
a.add(2);
a.add(3);
a.add(4);
b.add(1);
b.add(2);
b.add(3);
b.add(5);
for (Integer x : a) {
if (!b.contains(x)) {
exclusion.add(x);
}
}
for (Integer x : exclusion) {
System.out.println(x);
}
}
Try this...
Use the contains() method of List.
ArrayList<Integer> aList = new ArrayList<Integer>();
for (Integer i : a){
if (!(b.contains(i))){
aList.add(i);
}
else{
continue;
}
}
Ok I am relatively new to Java Programming, but have previous experience in C++. I want to search an array for a specific item, but what if there are more than one of the same specific item? Would it be best to use a temporary array to store all found items in the array and return the temporary array?
Note: I'm trying to find the best way of doing this with memory management and speed. And it's not for Home work:)
Use apache commons lib, which solve a lot of issues. Use this if you want to filter by predicate and select sub array
CollectionUtils.filter(
Arrays.asList(new Integer[] {1,2,3,4,5}),
new Predicate() {
public boolean evaluate(final Object object) {
return ((Integer) object) > 2;
}
}
);
In case if you would like to select item(s) use
CollectionUtils.select(Collection inputCollection, Predicate predicate)
Use true java way - Navigable set and maps
NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive);
If you able to skip Java, then in Scala it will be much easier:
scala> val a = Array(4, 6, 8, 9, 4, 2, 4, 2)
a: Array[Int] = Array(4, 6, 8, 9, 4, 2, 4, 2)
scala> a.filter(_ == 4)
res0: Array[Int] = Array(4, 4, 4)
just use guava library as the simplest solution:
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Iterables.html
or
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Collections2.html
Just use an ArrayList. Example:
/** Returns all strings starting with the letter a.*/
public static List<String> getStartsWithA(String[] strs) {
List<String> ret = new ArrayList<String>();
for (String s: strs) {
if (s.startsWith("a") || s.startsWith("A")) {
ret.add(s);
}
}
return ret;
}
ArrayList's internal array will dynamically grow as more space is needed.
I would use a "ready to use" implementation like a HashMap. You say "search", so I believe that you have a searchkey (in my proposal the String) under wich you can store your data (for example an Integer).
Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();
void storeValue(final String key, final Integer value) {
List<Integer> l = this.map.get(key);
if (l == null) {
synchronized (this.map) {
if (l == null) {
l = new Vector<Integer>();
this.map.put(key, l);
}
}
}
l.add(value);
}
List<Integer> searchByKey(final String key) {
return this.map.get(key);
}
With this, you can store multiple Integers # one key. Of course you can store other Object than the Integers.